Stragety Pattern

The policy pattern is a behavioral pattern that defines a series of algorithms, encapsulates each algorithm, and makes them interchangeable, allowing the algorithm to change independently of the customers using it.

Use policy patterns to separate behavior from context. The environment class is responsible for maintaining and querying the behavior class, and the various algorithms are provided in the concrete policy class.

role

1. Abstract Strategy

This is an abstract role, usually implemented by an interface or abstract class. This role gives all the interfaces required by the specific policy classes;

2. Concrete Strategy

Concrete policy classes that implement abstract policies and wrap associated algorithms or behaviors;

3. Context

Holds a reference to a Strategy class and can logically select the corresponding policy for the instance.

The sample



Namespace StragetyPattern contains the policy base class Tax and its eight implementation classes. The Context environment class holds the policy base class. This example calculates personal income taxes in an elegant way.

public abstract class Tax {

    protected decimal TaxRate = 0;

    protected decimal QuickDeduction = 0;

    public virtual decimal Calculate(decimal income) {
        returnincome * TaxRate - QuickDeduction; }}Copy the code

Tax refers to personal income Tax, TaxRate refers to Tax rate, QuickDeduction refers to quick calculation of personal income Tax, and Calculate refers to personal income Tax of corresponding income.

public class Level0 : Tax {

    public Level0() {
        TaxRate = 0.00m;
        QuickDeduction = 0; }}Copy the code

Level 0 individual income tax ladder, indicating the initial state of individual income tax.

public class Level1 : Tax {

    public Level1() {
        TaxRate = 0.03m;
        QuickDeduction = 0; }}Copy the code

Level 1 individual income tax ladder.

public class Level2 : Tax {

    public Level2() {
        TaxRate = 0.10m;
        QuickDeduction = 105; }}Copy the code

Level 2 individual income tax ladder.

public class Level3 : Tax {

    public Level3() {
        TaxRate = 0.20m;
        QuickDeduction = 555; }}Copy the code

Three individual income tax steps.

public class Level4 : Tax {

    public Level4() {
        TaxRate = 0.25m;
        QuickDeduction = 1005; }}Copy the code

Four individual income tax steps.

public class Level5 : Tax {

    public Level5() {
        TaxRate = 0.30m;
        QuickDeduction = 2755; }}Copy the code

Five individual income tax steps.

public class Level6 : Tax {

    public Level6() {
        TaxRate = 0.35m;
        QuickDeduction = 5505; }}Copy the code

Six individual income tax steps.

public class Level7 : Tax {

    public Level7() {
        TaxRate = 0.45m;
        QuickDeduction = 13505; }}Copy the code

Seven individual income tax steps.

public class Context {
 
    private Tax _tax = null;
 
    private const decimal EXEMPTION_VALUE = 3500m;
 
    private List<decimal> _taxLevel = new List<decimal> {0.1500.4500.9000.35000.55000.80000.decimal.MaxValue
    };
 
    private List<Type> _levels = new List<Type>();
 
    private void GetLevels() {
        _levels = AppDomain.CurrentDomain.GetAssemblies()
                           .SelectMany(tp => tp.GetTypes()
                           .Where(t => t.BaseType == typeof(Tax)))
                           .ToList();
    }
 
    public Context() {
        GetLevels();
    }
 
    public Context Calculate(decimal income) {
        _tax = new Level0();
        var result = income - EXEMPTION_VALUE;
        for(int i = 1; i <= _taxLevel.Count - 1; i++) {
            if(result > _taxLevel[i - 1] && result <= _taxLevel[i]) {
                _tax = (Tax)Activator.CreateInstance(_levels[i]);
            }
        }
        Console.WriteLine($"Income = {income}," + $"tax = {_tax.Calculate(result)}!");
        return this; }}Copy the code

EXEMPTION_VALUE ($3500 in this example), and then select the appropriate Tax implementation class using reflection and a few techniques to calculate the individual income Tax of the respective ladder.

public class Program {

    private static Context _context = new Context();

    public static void Main(string[] args) {
        _context.Calculate(2500.00m)
                .Calculate(4900.00m)
                .Calculate(5500.00m)
                .Calculate(7000.00m)
                .Calculate(10000.00m)
                .Calculate(16000.00m)
                .Calculate(43000.00m)
                .Calculate(70000.00m)
                .Calculate(100000.00m)
                .Calculate(4500.00m)
                .Calculate(1986.00m); Console.ReadKey(); }}Copy the code

Above is the caller’s code, Calculate is specially processed to support the method chain. Here is the output of this case:

Income = 2500.00,tax = 0.0000!
Income = 4900.00,tax = 42.0000!
Income = 5500.00,tax = 95.0000!
Income = 7000.00,tax = 245.0000!
Income = 10000.00,tax = 745.0000!
Income = 16000.00,tax = 2120.0000!
Income = 43000.00,tax = 9095.0000!
Income = 70000.00,tax = 17770.0000!
Income = 100000.00,tax = 29920.0000!
Income = 4500.00,tax = 30.0000!
Income = 1986.00,tax = 0.0000! 
Copy the code

advantages

1. The hierarchical structure of a policy class defines an algorithm or behavior family. Proper use of inheritance can move common code into the parent class to avoid duplicate code. Inheritance can handle multiple algorithms or behaviors, avoiding the use of multiple conditional transfer statements.

disadvantages

1. The client must know all the policy classes and decide which policy class to use. Policy mode creates many policy classes, resulting in a “subclass explosion”.

Usage scenarios

1. If there are many classes in a system that are distinguished only by their behavior, then using the policy pattern can dynamically make an object choose one behavior among many behaviors; A system needs to dynamically choose one of several algorithms.