This is the second day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021

An overview of the

First look at the picture below, we travel to choose a lot of modes, you can ride a bike, you can take a car, you can take a train, you can take a plane.

As a program ape, development needs to choose a development tool, of course, there are many tools for code development, you can choose Idea for development, you can also use Eclipse for development, you can also use some other development tools.

Definition:

The pattern defines a series of algorithms and encapsulates each algorithm so that they are interchangeable, and changes to the algorithm do not affect customers using the algorithm. The policy pattern belongs to the object behavior pattern. It encapsulates the algorithm, separates the responsibility of using the algorithm from the implementation of the algorithm, and assigns different objects to manage these algorithms.

structure

The main roles of the policy pattern are as follows:

  • Abstract Strategy Class: 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.
  • Concrete Strategy class: Interfaces that implement abstract policy definitions and provide Concrete algorithm implementations or behaviors.
  • Context class: Holds a reference to a policy class that is ultimately called by the client.

Case implementation

Promotional activities

A department store is planning its annual 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:

The code is as follows:

Common interface for all promotions in Dingyi Department Store

public interface Strategy {
    void show(a);
}
Copy the code

Concrete Strategy: Specific promotions for each holiday

// Promotional activities for the Spring Festival
public class StrategyA implements Strategy {

    public void show(a) {
        System.out.println("Buy one get one free"); }}// Promotional activities for Mid-Autumn Festival B
public class StrategyB implements Strategy {

    public void show(a) {
        System.out.println("$50 less over $200"); }}// Promotional activities for Christmas
public class StrategyC implements Strategy {

    public void show(a) {
        System.out.println("$1,000 plus $1 for any item under $200"); }}Copy the code

Define Context: Used to connect the Context, that is, to sell the promotion to the customer, in this case, the salesperson

public class SalesMan {                        
    // Holds a reference to the abstract policy role
    private Strategy strategy;                 
                                               
    public SalesMan(Strategy strategy) {       
        this.strategy = strategy;              
    }                                          
                                               
    // Show promotions to customers
    public void salesManShow(a){ strategy.show(); }}Copy the code

The advantages and disadvantages

1. Advantages:

  • You can switch between policy classes freely

    Since policy classes all implement the same interface, they can be switched freely between them.

  • extensible

    To add a new policy, you only need to add a specific policy class, and basically do not need to change the original code, which conforms to the “open closed principle”.

  • Avoid the use of multiple conditional selection statements (if else), fully embody the idea of object-oriented design.

2. Disadvantages:

  • The client must know all the policy classes and decide which one to use.
  • The policy pattern will result in many policy classes, and the number of objects can be reduced to some extent by using the share pattern.

Usage scenarios

  • When a system needs to dynamically select one of several algorithms, each algorithm can be encapsulated in a policy class.
  • A class defines multiple behaviors that occur as conditional statements in the actions of that class, and each conditional branch can be moved into its own policy class to replace those conditional statements.
  • Each algorithm in the system is completely independent of each other, and the implementation details of the specific algorithm are required to be hidden from customers.
  • Policy patterns can be used to hide data structures associated with algorithms when the system requires that customers using algorithms should not know the data they operate on.
  • Multiple classes differ only in their behavior, and you can use the policy pattern to dynamically select the specific behavior to be performed at run time.

JDK source code

Policy mode in the Comparator. There’s a sort() method in the Arrays class that looks like this:

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); }}}Copy the code

Arrays is an environment role class, and this sort method can pass Arrays a new policy to sort by. Take the following test class for example.

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

        Integer[] data = {12.2.3.2.4.5.1};
        // Implement descending sort
        Arrays.sort(data, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                returno2 - o1; }}); System.out.println(Arrays.toString(data));//[12, 5, 4, 3, 2, 2, 1]}}Copy the code

When we call the Sort method of Arrays, the second argument passes a subimplementation of the Comparator interface. So the Comparator acts as an abstract policy role, and the concrete subimplementation class acts as a concrete policy role. The environment roles classes should be called with references to abstract policies. Does the Sort method of the Arrays class implement the compare() method using the Comparator child? Let’s move on to the sort() method of the TimSort class, which looks like this:

class TimSort<T> {
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        assertc ! =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++;
        }

        returnrunHi - lo; }}Copy the code

In that code, we’ll end up in countRunAndMakeAscending(). As we can see, only the compare method is used, so when we call arrays. sort we just pass the class object of the specific compare overwrite method, which is a mandatory subclass of the Comparator interface.