Big Talk Design Patterns —— Strategic Patterns

Policy pattern: The algorithm family is defined and encapsulated separately so that they can replace each other. This pattern makes the algorithm change without affecting the customers who use the algorithm.
Application scenario: Frequently changing requirements can be abstracted into a policy class by using policy patterns, and then specific algorithms can implement abstract class methods to accomplish different functions.
Examples: Store cashiers will carry out different promotional activities, such as discounts, full reductions and so on.

Analysis: According to the demand, we can use the simple factory mode to achieve, but every time a new preferential type is added, we need to modify the factory method. This is not the best way. We can use the strategy mode to solve the problem of frequent changes in the algorithm.

Realization:

First, we abstract the essence of all activities CashSuper class, that is, the processing of the incoming amount, which is used as the base class.

/**
 * Abstract strategy: cash charging class, abstracting the common points of all algorithms
 */
public class CashSuper {

    /**
     * Interface method
     * @param money Receivables
     * @return  Actual receipts
     */
    public double acceptCash(double money){
        return money;
    }
}

Then we inherit the base class according to different requirements, rewrite the acceptCash method, and implement different algorithms.

Full minus active CashReturn class:

/**
 * Full charge reduction
 */
public class CashReturn extends CashSuper {

    /**
     * Amount to be met
     */
    private double moneyCondition;

    /**
     * Full reduction amount
     */
    private double moneyReturn;

    public CashReturn(double moneyCondition, double moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
        double result = money;
        if (result >= moneyCondition){
            result = money - moneyReturn * Math.floor(money / moneyCondition);
        }
        return result;
    }
}

CashRebate for discount activities:

/**
 * Discount charge
 */
public class CashRebate extends CashSuper {

    /**
     * Discount rate
     */
    private double moneyRebate;

    public CashRebate(double moneyRebate) {
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
        return money * moneyRebate;
    }
}

Define a policy class:

/**
 * Implementing Basic Strategy Patterns
 */
public class BaseCashContext {
    private CashSuper cashSuper;

    public BaseCashContext(CashSuper cashSuper) {
        this.cashSuper = cashSuper;
    }

    public double getResult(double money){
        return cashSuper.acceptCash(money);
    }
}

The above code implements a basic policy pattern. The following is the test class:

/**
 * Policy pattern test class
 */
public class StrategyTest {

    public static double baseCashContext(String type, double money){
        BaseCashContext baseCashContext = null;
        switch (type){
            case "Normal charge":
                baseCashContext = new BaseCashContext(new CashNormal());
                break;
            case "Full 300 minus 30":
                baseCashContext = new BaseCashContext(new CashReturn(300, 30));
                break;
            case "Hit 20 percent off":
                baseCashContext = new BaseCashContext(new CashRebate(0.8));
                break;
            default:
                break;
        }
        return baseCashContext.getResult(money);
    }

    public static void main(String[] args){
        String type = "Normal charge";
        double money = 300;
        // Basic Strategic Model
        System.out.println(baseCashContext(type, money));

    }
}

Strategic model versus simple factory model:
Simple factory mode requires the client to recognize two classes, CashSuper and CashFactory, while policy mode only requires the client to recognize one CashContext class.
The coupling degree of policy mode is lower. In the policy mode, the client instantiates the CashContext object and calls the method getResult() of CashContext, which makes the specific charging algorithm completely separate from the client. Even the parent class of the algorithm does not need to be recognized by the client.

If you want to further reduce the complexity of the client, you can combine the policy pattern with the simple factory pattern. The policy class can be written in the following way:

/**
 * Combining the policy pattern with the simple factory pattern: invoking different methods according to the incoming policy
 */
public class CashContext {

    private CashSuper cashSuper;

    public CashContext(String type) {
        switch (type){
            case "Normal charge":
                cashSuper = new CashNormal();
                break;
            case "Full 300 minus 30":
                cashSuper = new CashReturn(300, 30);
                break;
            case "Hit 20 percent off":
                cashSuper = new CashRebate(0.8);
                break;
            default:
                break;
        }
    }

    public double getResult(double money){
        return cashSuper.acceptCash(money);
    }
}

Test methods:

/**
 * Policy pattern test class
 */
public class StrategyTest {

    public static double cashContext(String type, double money){
        CashContext cashContext = new CashContext(type);
        return cashContext.getResult(money);
    }

    public static void main(String[] args){
        String type = "Normal charge";
        double money = 300;
        // Combining Strategic Model with Simple Factory Model
        System.out.println(cashContext(type, money));
    }

}

Basic Strategy Model and Strategy Model-Simple Factory Model Combination Contrast:
In the basic policy pattern, the responsibility of selecting the specific implementation used is assumed by the client and transferred to the Context object of the policy pattern. This in itself does not relieve the pressure of the client to choose judgment, and the responsibility of choosing specific implementation can also be assumed by Context after the combination of policy mode and simple factory mode, which minimizes the responsibility of the client.
This is better than the original policy mode, but switch is still used in CashContext, that is to say, if you add a "full 200 to 20" switch or change the switch in CashContext, reflection technology will be used to solve this problem (in the subsequent abstract factory mode).

Policy pattern analysis:
Policy pattern is a method of defining a series of algorithms. Conceptually, all algorithms accomplish the same work, but implement differently. It can call all algorithms in the same way, reducing the coupling between various algorithms and using algorithms.
The Strategy class hierarchy of policy patterns (CashSuper class) defines a series of reusable algorithms or behaviors for the Context class. Inheritance helps to dismantle the common functions of these algorithms (the getResult() method).
The application of strategy pattern:
The main function of policy pattern is to encapsulate changes. In practical application, as long as different business rules need to be applied at different times, the possibility of using policy pattern to deal with such changes can be considered.

Added by Chris.P on Fri, 17 May 2019 04:14:05 +0300