Design Patterns_Behavioral Patterns - "Strategy Patterns"

Design Patterns_Behavioral Patterns - "Strategy Patterns"

The notes are organized from the detailed explanation of Java design patterns by dark horse programmers, 23 Java design patterns (diagram + framework source code analysis + actual combat)

overview

Let’s look at the picture below first. There are many modes of travel for us to choose from. We can ride a bicycle, take a car, take a train, or take an airplane.

As a programmer, you need to choose a development tool for development. Of course, there are many tools for code development. You can choose idea for development, you can also use eclipse for development, and you can also use some other development tools.

definition

  • This mode defines a series of algorithms and encapsulates each algorithm so that they can be replaced with each other, and the change of the algorithm will not affect the customers who use the algorithm. The strategy pattern belongs to the object behavior pattern. It encapsulates the algorithm, separates the responsibility of using the algorithm from the realization of the algorithm, and delegates to different objects to manage these algorithms.

structure

The main roles of the Strategy Pattern are as follows:

  • Abstract Strategy (Strategy) class: This is an abstract role, usually implemented by an interface or abstract class. This role gives all interfaces required by the concrete strategy classes.
  • Concrete Strategy (Concrete Strategy) class: implements the interface defined by the abstract strategy, and provides specific algorithm implementation or behavior.
  • Environment (Context) class: Holds a reference to a strategy class, which is eventually called by the client.

Case realization

【Example】Promotion

A department store is holding an annual sales promotion. Launch different promotional activities for different festivals (Spring Festival, Mid-Autumn Festival, Christmas), and the promoters will show the promotional activities to customers. The class diagram is as follows:

code show as below:

  • Define a common interface for all promotions in a department store

    // 抽象策略类
    public interface Strategy {
          
          
        void show();
    }
    
  • Define specific strategic roles (Concrete Strategy): specific promotional activities for each festival

    // 具体策略类-为春节准备的促销活动A
    public class StrategyA implements Strategy {
          
          
    
        public void show() {
          
          
            System.out.println("买一送一");
        }
    }
    
    // 具体策略类-为中秋节准备的促销活动B
    public class StrategyB implements Strategy {
          
          
    
        public void show() {
          
          
            System.out.println("满200元减50元");
        }
    }
    
    // 具体策略类-为圣诞节准备的促销活动C
    public class StrategyC implements Strategy {
          
          
    
        public void show() {
          
          
            System.out.println("满1000元加一元换购任意200元以下商品");
        }
    }
    
  • Define the role of the environment (Context): used to connect the context, that is, to sell promotional activities to customers, here it can be understood as a salesperson

    // 环境类-销售员
    public class SalesMan {
          
          
        
        // 聚合策略类 持有抽象策略角色的引用                              
        private Strategy strategy;                 
                                                   
        public SalesMan(Strategy strategy) {
          
                 
            this.strategy = strategy;              
        }                                          
                          
        // 向客户展示促销活动                                
        public void salesManShow(){
          
                          
            strategy.show();                       
        }                                          
    }                                              
    
  • test class

    public class Client {
          
          
        public static void main(String[] args) {
          
          
            // 春节来了,使用春节促销活动
            SalesMan salesMan = new SalesMan(new StrategyA());
            // 展示促销活动
            salesMan.salesManShow();
    
            System.out.println("==============");
            // 中秋节到了,使用中秋节的促销活动
            salesMan.setStrategy(new StrategyB());
            // 展示促销活动
            salesMan.salesManShow();
    
            System.out.println("==============");
            // 圣诞节到了,使用圣诞节的促销活动
            salesMan.setStrategy(new StrategyC());
            // 展示促销活动
            salesMan.salesManShow();
        }
    }
    

    output

    买一送一
    ==============
    满200元减50元
    ==============
    满1000元加一元换购任意200元以下商品
    

Advantages and disadvantages

advantage

  • Freely switch between strategy classes
    • Since the strategy classes all implement the same interface, they can be switched freely.
  • easy to expand
    • To add a new strategy, you only need to add a specific strategy class, and basically do not need to change the original code, which conforms to the "opening and closing principle".
  • Avoid using multiple conditional selection statements (if else), fully embody the object-oriented design idea.

shortcoming

  • All policy classes need to be exposed to the outside world, and the client must know all policy classes and decide which one to use.
  • The strategy pattern will generate many strategy classes, and the number of objects can be reduced to a certain extent by using the flyweight pattern.

scenes to be used

  • When a system needs to dynamically select one of several algorithms, each algorithm can be encapsulated into a strategy class.
  • A class defines multiple behaviors, and these behaviors appear in the form of multiple conditional statements in the operation of this class. Instead of these conditional statements, each conditional branch can be moved into its own strategy class.
  • Each algorithm in the system is completely independent of each other, and it is required to hide the implementation details of the specific algorithm from the client.
  • When the system requires that clients using the algorithm should not know the data it operates on, the strategy pattern can be used to hide the data structures associated with the algorithm.
  • The only difference between multiple classes is that they behave differently. You can use the strategy mode to dynamically select the specific behavior to be executed at runtime.

JDK source code analysis - Comparator

Comparatorstrategy pattern in . There is a method in the Arrays class sort(), as follows:

public class Arrays{
    
    
    public static <T> void sort(T[] a, Comparator<? super T> c) {
    
    
        if (c == null) {
    
    
            sort(a);
        } else {
    
    
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }
}

Arrays is an environment role class. The sort method can pass a new strategy to make Arrays sort according to this strategy. For example, the following test class.

public class demo {
    
    
    public static void main(String[] args) {
    
    

        Integer[] data = {
    
    12, 2, 3, 2, 4, 5, 1};
        // 实现降序排序
        Arrays.sort(data, new Comparator<Integer>() {
    
    
            public int compare(Integer o1, Integer o2) {
    
    
                return o2 - o1;
            }
        });
        System.out.println(Arrays.toString(data)); // [12, 5, 4, 3, 2, 2, 1]
    }
}

Here, when we call the sort method of Arrays, the second parameter is the sub-implementation class object of the Comparator interface. So Comparator acts as an abstract strategy role, while the specific sub-implementation class acts as a concrete strategy role. Ambient role classes (Arrays) should hold references to abstract policies to invoke. So, does the sort method of the Arrays class use the method in the Comparator sub-implementation class compare()? Let us continue to look at sort()the method of the TimSort class, the code is as follows:

class TimSort<T> {
    
    
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
    
    
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
    
    
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }
        ...
    }   

    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator<? super T> c) {
    
    
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        if (c.compare(a[runHi++], a[lo]) < 0) {
    
     // Descending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {
    
                                  // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }
}

The above code will eventually run countRunAndMakeAscending()into this method. We can see that the method is called in this method c.compare(), so when calling the Arrays.sort method, only the class object of the specific compare override method is passed. This is also a method that must be implemented by subclasses in the Comparator interface. This is the embodiment of the strategy pattern.

Strategy pattern for thread pool - rejection strategy

Reference article: Thread Pool - Detailed Explanation of ThreadPoolExecutor - Custom Thread Pool .

Guess you like

Origin blog.csdn.net/weixin_53407527/article/details/128627989