头图

front

  • Take notes on learning design patterns
  • Improve flexible use of design patterns

Learning address

">https://www.bilibili.com/video/BV1G4411c7N4

">https://www.bilibili.com/video/BV1Np4y1z7BU

Reference article

http://c.biancheng.net/view/1317.html

Project source code
https://gitee.com/zhuang-kang/DesignPattern

26. Strategy mode

26.1 Definition and characteristics of the strategy model

Definition of Strategy mode: 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. strategy mode belongs to the object behavior mode. It encapsulates the algorithm, separates the responsibility of using the algorithm and the realization of the algorithm, and delegates to different objects to manage these algorithms.

strategy mode are as follows.

  1. Multiple conditional statements are not easy to maintain, and the use of strategy mode can avoid the use of multiple conditional statements, such as if...else statement, switch...case statement.
  2. The strategy pattern provides a series of reusable algorithm families. Proper use of inheritance can transfer the common code of the algorithm family to the parent class to avoid duplication of code.
  3. The strategy mode can provide different realizations of the same behavior, and customers can choose different ones according to different time or space requirements.
  4. The strategy mode provides perfect support for the opening and closing principle, and new algorithms can be flexibly added without modifying the original code.
  5. The strategy mode puts the use of the algorithm in the environment class, and the realization of the algorithm moves to the specific strategy class, realizing the separation of the two.

The main disadvantages of

  1. The client must understand the difference between all strategy algorithms in order to select the appropriate algorithm class at the right time.
  2. The strategy mode creates a lot of strategy classes, which increases the difficulty of maintenance.

26.2 The structure and implementation of the strategy pattern

26.2.1 The structure of the strategy pattern

  1. Abstract strategy (Strategy) class: defines a public interface, and various algorithms implement this interface in different ways. Environmental actors use this interface to call different algorithms, generally implemented by interfaces or abstract classes.
  2. Concrete Strategy (Concrete Strategy) class: implements the interface defined by the abstract strategy and provides specific algorithm implementation.
  3. Environment (Context) class: Holds a reference to a strategy class and is finally called by the client.

26.2.2 Code Implementation

Different promotions for different holidays

Relationship class diagram

image

Strategy

package com.zhuang.strategy;

/**
 * @Classname Strategy
 * @Description 定义共同接口
 * @Date 2021/3/31 15:29
 * @Created by dell
 */

public interface Strategy {
    void show();
}

StrategyA

package com.zhuang.strategy;

/**
 * @Classname StrategyA
 * @Description 定义具体策略角色 每个节日的具体促销活动
 * @Date 2021/3/31 15:29
 * @Created by dell
 */

public class StrategyA implements Strategy {

    @Override
    public void show() {
        System.out.println("A促销 买一送一");
    }
}

StrategyB

package com.zhuang.strategy;

/**
 * @Classname StrategyB
 * @Description 定义具体策略角色 每个节日的具体促销活动
 * @Date 2021/3/31 15:30
 * @Created by dell
 */

public class StrategyB implements Strategy {

    @Override
    public void show() {
        System.out.println("B促销 满100减20");
    }
}

StrategyC

package com.zhuang.strategy;

/**
 * @Classname StrategyC
 * @Description 定义具体策略角色 每个节日的具体促销活动
 * @Date 2021/3/31 15:30
 * @Created by dell
 */

public class StrategyC implements Strategy {

    @Override
    public void show() {
        System.out.println("C促销 满500元可兑换小礼品");
    }
}

SalesMan

package com.zhuang.strategy;

/**
 * @Classname SalesMan
 * @Description 定义环境角色 用于连接上下文 把促销活动推销给顾客
 * @Date 2021/3/31 15:32
 * @Created by dell
 */

public class SalesMan {

    //持有抽象策略角色的引用
    private Strategy strategy;

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

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    //展示促销活动
    public void salesManShow() {
        strategy.show();
    }
}

Client

package com.zhuang.strategy;

/**
 * @Classname Client
 * @Description 策略模式 测试类
 * @Date 2021/3/31 15:34
 * @Created by dell
 */

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();
    }
}

image

26.3 Application Scenarios of Strategy Mode

  • 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. Each conditional branch can be moved into their respective strategy classes to replace these conditional statements.
  • When the algorithms in the system are completely independent of each other, and the implementation details of specific algorithms are required to be hidden from customers.
  • When the system requires that the customer who uses the algorithm should not know the data of its operation, the strategy mode can be used to hide the data structure related to the algorithm.
  • Multiple classes only differ in their performance behaviors. You can use the strategy mode to dynamically select specific behaviors to be executed at runtime.

26.4 JDK source code analysis

The strategy mode in Comparator sort() method in the Arrays class, 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 sort Arrays 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 passed the sub-implementation class object of the Comparator interface. So the Comparator acts as an abstract strategy role, and the concrete sub-implementation class acts as a concrete strategy role. The environment role class (Arrays) should be called with a reference to the abstract strategy. So, does the sort method of the Arrays class use the compare() method in the Comparator sub-implementation class? Let us continue to look at the sort() 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() the method 0610a65289c20a. We can see that only the compare method is used, 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 the subclass in the Comparator interface.

written at the end

  • If my article is useful to you, please give me some 👍, thank you 😊!
  • If you have any questions, please point them out in the comment area! 💪

康小庄
12 声望6 粉丝

代码不停,思考不止.