Strategic mode of design mode

Posted by happyness on Thu, 27 Jan 2022 20:26:36 +0100

Design principles of java program

6 principles:

Single responsibility: a class and method do only one thing.
Open / close: close the modification and expand the development.
Richter substitution: subclasses can extend new methods, but cannot modify the existing methods of the parent class (the parent class has provided specific implementation methods).
Dependency inversion: it depends on abstraction rather than concrete implementation, that is, interface oriented programming (for example, method parameters and class attributes use interface declaration, so that any subclass can be received).
Interface isolation: use multiple isolated interfaces to define abstraction and reduce coupling.
At least know/Dimitt: reduce dependencies, aggregation, composition, etc. between classes.

1: Strategy design pattern

The general use scenario of strategy design pattern is that many kinds of similar behaviors can be substituted for each other. In the specific operation process, according to different situations, one of the behaviors is chosen to execute, such as payment, WeChat payment, Alipay payment and bank card payment. Then, which payment method should be used, which is decided by users, such as shopping preferences. Users can choose to use coupons, full discount, and other preferential methods. It is up to the user to decide which preferential method to use. In similar scenarios, we can consider using the strategy design mode. Perhaps for similar scenarios, ifelse is the most commonly used one. The disadvantage of ifelse is that it lacks scalability and does not comply with the opening and closing principles from the six principles, Let's look at how to use the strategy design pattern through a practical scenario.

1.1: scenario

When we shop, we often have preferential activities as shown in the figure:

Direct reduction: for example, in the double 11 and other times, businesses will choose this way to promote sales. For example, for goods with the original price of 999, they will directly reduce the price to 899.
Full minus: it is generally issued to users in the form of coupons. When the user's consumption amount reaches a certain amount, the coupons are directly used to deduct a certain amount of cash, as shown in the figure "full 2000 minus 1000", the total price is 2999, and 2899 is required after using the coupons.
Discount: merchants directly sell goods at a discount. For example, goods with an original price of 1000 yuan are directly sold at a 20% discount, and the actual price is 800 yuan.
N Yuan purchase: another marketing method, such as buying a mobile phone of 1999 yuan for 1 yuan, but it is not 100% available, but has a certain probability, which is similar to buying lottery tickets.

After understanding the above preferential activities, let's first look at how to realize it through conventional if else. For details, refer to 1.2: if else.

1.2: if else implementation

The sample code is as follows, which is used to calculate the amount that the user actually needs to pay (it is only an example, but does not provide a real implementation):

class FakeCls {
    // type: preferential method
    // 1: Direct reduction 2: full reduction 3: discount 4: N yuan purchase
    double needPayAmount(int type, String otherParams) {
        if (type == 1) {
            // Direct subtraction related logic
        } else if (type == 2) {
            // Full minus correlation logic
        } else if (type == 3) {
            // Discount related logic
        } else if (type == 4) {
            // N-yuan purchase related logic
        }
    }   
}

The above code obviously does not conform to the single responsibility and opening and closing principle in the six design principles. In this way, the expansibility of writing code is very weak and the cost of modifying code is high, It has a great impact on the existing functions (maybe the modification of your line of code makes the old functions difficult to use. You say whether to test or not. If not, it is obviously affected. Testing will increase the workload of others). Next, let's see how to use the strategic design pattern to optimize the code.

1.3: strategy design pattern implementation

First, according to the dependency inversion principle, we need an interface, as follows:

public interface PayAmount {
    double payAmount(Object param);
}

Then, according to the principle of single responsibility, we provide a specific implementation class for each preferential method.

  • Direct reduction
// Direct reduction
public class DecreasePayAmount implements PayAmount {
    @Override
    public double payAmount(Object param) {
        System.out.println("Payment by direct reduction");
        return 0;
    }
}
  • Full minus
// Full minus
public class CouponPayAmount implements PayAmount {
    @Override
    public double payAmount(Object param) {
        System.out.println("Use full minus payment");
        return 0;
    }
}
  • discount
// discount
public class DiscountPayAmount implements PayAmount {
    @Override
    public double payAmount(Object param) {
        System.out.println("Payment by discount");
        return 0;
    }
}
  • N yuan purchase
// N yuan purchase
public class NYuanPayAmount implements PayAmount {

    @Override
    public double payAmount(Object param) {
        System.out.println("use N Yuan purchase payment");
        return 0;
    }
}

Next, define the policy class:

public class PayAmountStrategy {
    // Dependency inversion principle, interface oriented programming
    private PayAmount payAmount;

    public PayAmountStrategy(PayAmount payAmount) {
        this.payAmount = payAmount;
    }

    public double payAmount(Object param) {
        return this.payAmount.payAmount(param);
    }
}
  • test
public class StrategyDesignPatternTest {

    public static void main(String[] args) {
        // Full minus
        new PayAmountStrategy(new CouponPayAmount()).payAmount(null);
        // Direct reduction
        new PayAmountStrategy(new DecreasePayAmount()).payAmount(null);
        // discount
        new PayAmountStrategy(new DiscountPayAmount()).payAmount(null);
        // N yuan purchase
        new PayAmountStrategy(new NYuanPayAmount()).payAmount(null);
    }
}

function:

Use full minus payment
 Payment by direct reduction
 Payment by discount
 use N Yuan purchase payment

In practical work, it does not have to be done in this way, but can also be changed and adjusted according to the actual situation, but the core remains unchanged.

List of reference articles

Topics: Java Design Pattern