Design mode [12] - the strategy mode to solve the recent fire

Posted by jeny on Sun, 23 Jan 2022 22:48:33 +0100

It's still the beginning. The strategy mode seems to be very popular recently. Please look down

What is the strategic model?

In fact, we have explained the structural mode before, and the rest are all behavioral modes. The distinction between the three modes is as follows:

  • Creative mode: how to create an object
  • Structural pattern: how is the structure inside the object constructed
  • Behavioral patterns: how objects work (what they can do)

When it comes to strategic models, how should we understand them?

  • From Beijing to Shanghai, you can take a plane, a bullet train, a green leather, or even a bicycle. These different ways are strategy.

  • For a commodity, you can directly give a 50% discount, add 100 and give a 60% discount, or give a 5.5% discount and return the cash coupon. These are also strategies.

  • Take 200 to the supermarket to buy things. You can buy snacks, daily necessities or nothing. These are also strategies.

In the above example, in fact, we can find that different strategies are interchangeable, and even policy details can be mixed and matched. In order to facilitate expansion and replacement of policies, we can use the policy model by shielding different policy details from the caller. If all the strategies are written in one class, it can be. In this way, the maintenance code will become more and more complex, and the maintenance will only become more and more difficult. It will be filled with all kinds of if else. If the algorithm becomes more and more complex, it will only be left to run with a bucket.

Policy mode refers to a relatively stable policy name with certain action content. In ancient times, the strategy model was also called "strategy", which was abbreviated as "strategy". For example, in the book of Han Dynasty · emperor Gaodi Ji Shang: "the king of Han followed his plan". The "plan" here refers to stratagem and strategy. The strategy model has relatively stable forms, such as "avoiding the truth and avoiding the emptiness", "winning by surprise" and so on. A certain strategic model can be applied to both strategic and tactical decision-making; It can be implemented not only in the global action of large-scale system, but also in the local action of large-scale system.

Another example known to all migrant workers is that everyone has to pay personal income tax. We know that the calculation method of personal income tax is very complex. Tax law calculation is a behavior, and there may be different implementation algorithms. Each calculation algorithm is a strategy.

These policies may be replaced at any time. In order to facilitate replacement and isolate each other, we define a series of algorithms and encapsulate them, which is called policy pattern.

Role of policy mode

The policy mode generally has three roles:

  • Abstract Strategy: abstracts the behavior of a policy from a public interface
  • Concrete Strategy: the Strategy interface is used to implement some specific algorithms. There may be multiple specific strategies or they can be replaced with each other
  • Context: generally, it encapsulates the policy and the use method of the policy, shields the details of the upper layer call, and can be called directly.

demo of policy mode

Create an abstract policy interface:

public interface Strategy {

    int doStrategy();
}

Create two specific policy classes to execute policies respectively:

public class ConcreteStrategy1 implements Strategy{
    @Override
    public int doStrategy() {
        System.out.println("Execute strategy 1...");
        return 1;
    }
}
public class ConcreteStrategy2 implements Strategy{
    @Override
    public int doStrategy() {
        System.out.println("Execution strategy 2...");
        return 2;
    }
}

Create a context class to encapsulate the policy class:

public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy(){
        strategy.doStrategy();
    }
}

Test class:

public class Test {
    public static void main(String[] args) {
        Context context1 = new Context(new ConcreteStrategy1());
        context1.executeStrategy();

        context1 = new Context(new ConcreteStrategy2());
        context1.executeStrategy();
    }
}

Test results:

Execute strategy 1
 Execution strategy 2

You can see that different results can be performed as long as different strategies are used.

Bonus package strategy practice

For example, there are allocation strategies involved in the work. The scenario is that there are red envelopes assigned to several individuals, but there will be different allocation strategies. The different allocation strategies here are actually implemented in the policy mode. It can be randomly distributed, evenly distributed, distributed according to various weights, etc. Only two kinds of assignments are shown here:

First, define a red envelope class that contains the red envelope amount (we save integers in fractions to avoid inaccurate decimal amounts)

public class RedPackage {
    public int remainSize;

    public int remainMoney;

    public RedPackage(int remainSize, int remainMoney) {
        this.remainSize = remainSize;
        this.remainMoney = remainMoney;
    }
}

Define an abstract class of allocation policy:

import java.util.List;

public interface AllocateStrategy {

    List<Integer> allocate(RedPackage redPackage);

}

If it cannot be evenly distributed, the first place will increase or decrease:

import java.util.ArrayList;
import java.util.List;

public class AverageAllocateStrategy implements AllocateStrategy {
    @Override
    public List<Integer> allocate(RedPackage redPackage) {
        List<Integer> results = new ArrayList<>();
        Integer sum = redPackage.remainMoney;
        Integer average = sum / redPackage.remainSize;
        for (int i = 0; i < redPackage.remainSize; i++) {
            sum = sum - average;
            results.add(average);
        }
        if (sum != 0) {
            results.set(0, results.get(0) + sum);
        }
        return results;
    }
}

During random allocation, we will add each copy to the red envelope at random, but this can not guarantee the amount of each copy (note that this should not be used in production, but only for testing)

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class RandomAllocateStrategy implements AllocateStrategy {
    @Override
    public List<Integer> allocate(RedPackage redPackage) {
        return ranRedPackage(redPackage.remainSize, redPackage.remainMoney);
    }

    public List<Integer> ranRedPackage(Integer count, Integer money) {
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            result.add(0);
        }
        for (int i = 1; i <= money; i++) {
            int n = new Random().nextInt(count);
            result.set(n, result.get(n) + 1);
        }
        return result;
    }

}

Define context classes to encapsulate different policies:

import java.util.List;

public class Context {
    private AllocateStrategy strategy;

    public Context(AllocateStrategy strategy) {
        this.strategy = strategy;
    }

    public List<Integer> executeStrategy(RedPackage redPackage){
        return strategy.allocate(redPackage);
    }
}

Test class:

import java.util.List;

public class Test {
    public static void main(String[] args) {
        RedPackage redPackage = new RedPackage(10,102);
        Context context = new Context(new RandomAllocateStrategy());
        List<Integer> list =context.executeStrategy(redPackage);
        list.forEach(l-> System.out.print(l+" "));

        System.out.println("");
        context = new Context(new AverageAllocateStrategy());
        list =context.executeStrategy(redPackage);
        list.forEach(l-> System.out.print(l+" "));
    }
}

It can be seen that the allocated amount will indeed change with different policy classes:

9 10 16 8 14 8 7 15 9 6 
12 10 10 10 10 10 10 10 10 10 

Note that this cannot be used in production!!!

Advantages and disadvantages

Advantages of policy mode:

  • Eliminate if else statements, and separate different strategies to facilitate maintenance
  • Switch free
  • Good expansibility, just implement the interface

Disadvantages of policy mode:

  • Once the number of policies is too large, it will be relatively difficult to maintain and reuse code
  • All policy classes are exposed, although they are generally called through the Context

Strategy mode is commonly used. Some students may confuse strategy mode and status mode:

Relative to the state mode: the policy mode will execute the method only once, and the state mode will continuously execute the state change method as the state changes. For example, when we go from place A to place B, the strategy is to fly or train, and the state mode is that we may go to one place, change one mode of transportation, and change another mode of transportation to another place.

Summary

Policy patterns are commonly used. The core is to isolate different policies, encapsulate specific algorithms in policies, abstract a policy abstract class, and inject different specific policy classes into context classes to achieve the purpose of selecting different policies.

However, if there are many policies, reuse needs to be considered. When the policy class is exposed, the risk of abuse needs to be considered, which will destroy the encapsulation.

[about the author]:
Qin Huai, the official account of Qin Huai grocery store, author's personal website: http://aphysia.cn , the road of technology is not for a while, with high mountains and long rivers. Even if it is slow, it will not stop.

Design pattern series:

Topics: Design Pattern