Follow the public account “Java backend technology full Stack” reply “000” to obtain a large number of e-books

This article is the third in a series of design patterns:

Template pattern

The singleton pattern

Today, I would like to share with you the strategic model. The specific outline is as follows:

Life case

In the age of the Internet, especially in cities, there are a group of people riding electric scooter, shuttling through the streets and alleys, these people are the delivery boys.

I’ve ordered a lot of take-out. Once, when I was ordering takeout, I suddenly thought of a design pattern — strategic pattern.

What is a strategic pattern?

Strategy Pattern: Strategy Pattern refers to the definition and encapsulation of algorithm families so that they can be replaced with each other. This design Pattern ensures that the changes of algorithms will not affect users who use algorithms.

English

Define a family of algorithms,encapsulate each one,and make them interchangeable.

Define a set of algorithms, encapsulate each algorithm, and make them interchangeable.

In policy mode, the behavior of a class or its algorithm can be changed at run time. This type of design pattern is behavioral.

Policy pattern common code

Java code implementation is as follows:

class Client {

    // Abstract Strategy class Strategy
    interface IStrategy {
        void algorithm(a);
    }

    // ConcreteStrategy class
    static class ConcreteStrategyA implements IStrategy {

        @Override
        public void algorithm(a) {
            System.out.println("Strategy A"); }}// ConcreteStrategy class
    static class ConcreteStrategyB implements IStrategy {

        @Override
        public void algorithm(a) {
            System.out.println("Strategy B"); }}// Context
    static class Context {
        private IStrategy mStrategy;

        public Context(IStrategy strategy) {
            this.mStrategy = strategy;
        }

        public void algorithm(a) {
            this.mStrategy.algorithm(); }}public static void main(String[] args) {
        // Select a specific strategy
        IStrategy strategy = new ConcreteStrategyA();
        // Create a context
        Context context = new Context(strategy);
        // The client directly tells the context to execute the algorithmcontext.algorithm(); }}Copy the code

From the generic code above, we can see its UML diagram.

Policy pattern UML diagrams

Roles in the policy pattern

From the UML class diagram, we can see that the policy pattern consists of three main roles:

  • Context: The Context used to operate policies, shielding high-level modules (clients) from direct access to policies and algorithms, and encapsulating possible changes;

  • Abstract policy role (Strategy) : specifies the behavior of a policy or algorithm;

  • ConcreteStrategy roles: ConcreteStrategy or algorithm implementation;

Advantages and disadvantages of strategic pattern

advantages

  • The policy pattern conforms to the open close principle

  • Avoid multiple conversion statements, such as if… Else, switch statements.

  • Using the policy pattern can improve the confidentiality and security of the algorithm

disadvantages

  • The client must know all the policies and decide for itself which one to use

  • Many policy classes are generated in the code, which increases the difficulty of later maintenance

Application scenarios of policy mode

In daily development, the policy pattern applies to three scenarios:

  • There are multiple approaches to the same type of problem, each of which can solve the problem independently.

  • Scenarios where the algorithm needs to switch freely.

  • Scenarios where algorithm rules need to be masked

This is not easy to understand.

Let’s use life examples to see how the strategy pattern works.

Payment case code refactoring, three versions

When placing orders outside and choosing payment methods, I think this function can be realized by imitating the strategy mode. Let’s do this through three iterations, which is interesting.

The first edition

Let’s define an abstract class Pay:

// Define the abstract class. We can implement some common functions in the abstract class
// For example: compare the available balance with the payment amount, and return "payment failed" uniformly.
public abstract class  Pay {
    abstract  void doPay(a);
}

Copy the code

The following three payment methods are simulated:

public class AliPay extends Pay {
    @Override
    public void doPay(a) {
        System.out.println("Pay with Alipay"); }}public class UnionPay extends Pay {
    @Override
    public void doPay(a) {
        System.out.println("Pay with Union Pay"); }}public class WechatPay extends Pay {
    @Override
    public void doPay(a) {
        System.out.println("Use wechat Pay"); }}Copy the code

Let’s pay again:

public class PayTest {
    public static void main(String[] args) {
        // Give the user the option
        Order order = new Order(newWechatPay()); order.pay(); *}}Copy the code

Running results:

Use wechat PayCopy the code

This allowed us to implement the simple version of payment using the policy pattern, but one of the annoying things was that we had to manually new a payment method object each time. With this in mind, we refactored the first version.

The second edition

The previous implementation is unchanged, the change is to initiate the payment, as long as the front end passes a key can be, implementation as follows:

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

        String payKey = "Wechat";
        Order order = null;
        // Determine which payment method to use by judging the key passed from the front end
        if (payKey.equals("Ali")) {
            order = new Order(new AliPay());
        } else if (payKey.equals("Wechat")) {
            order = new Order(new WechatPay());
        } else if (payKey.equals("union")) {
            order = new Order(new UnionPay());
        }else {
            // Give a default
            order = new Order(newWechatPay()); } order.pay(); }}Copy the code

The results

Use wechat PayCopy the code

So here we are, with the key passed in from the front end, picking out the payment method. If there are more and more ways to pay, then if… There will be more and more else? Aren’t subsequent maintenance costs getting bigger and bigger?

Thus, the third edition was born.

The third edition

In version 2, there will be a lot of if… Else is inconvenient for subsequent code maintenance, so in this release, we refactor it to introduce the registered singleton pattern.

import java.util.HashMap;
import java.util.Map;

public enum PayStrategyEnum {
    ALI_PAY("Ali"),
    WECHAT_PAY("Wechat"),
    UNION_PAY("union"),
    // Wechat pay is used by default
    DEFAULT_PAY("Wechat");

    private String key;

    PayStrategyEnum(String key) {
        this.key = key;
    }

    private static final Map<String, Pay> payKeyMap = new HashMap();

    static {
        payKeyMap.put(ALI_PAY.key, new AliPay());
        payKeyMap.put(WECHAT_PAY.key, new WechatPay());
        payKeyMap.put(UNION_PAY.key, new UnionPay());
        payKeyMap.put(DEFAULT_PAY.key, new WechatPay());
    }

    public static Pay getPay(String payKey) {
        if(! payKeyMap.containsKey(payKey)) {return payKeyMap.get(DEFAULT_PAY.key);
        }
        returnpayKeyMap.get(payKey); }}Copy the code

Then, when the order is paid, it looks like this:

public class PayTest {
    public static void main(String[] args) { 
        String payKey = "Wechat"; 
        Order order = newOrder(PayStrategyEnum.getPay(payKey)); order.pay(); }}Copy the code

The results

Use wechat PayCopy the code

In this way, we successfully circumvent a lot of if… Else, cool!

In fact, the above three versions of the code, do not feel good, this is the design pattern is powerful.

PS: As for the above three versions, we can actually continue to improve, continue to refactor, if you are interested in how to continue to refactor.

conclusion

Well, that’s all for today’s strategy mode. In fact, in most cases, design patterns do not exist in isolation, but are used in a mixture of multiple design patterns.

The strategy pattern uses object-oriented inheritance and polymorphism mechanisms to achieve different implementations of the same behavior in different scenarios.

Best examples to remember:

We can use different means of transportation to go to Beijing

By plane, by bullet train, by car, by car, by bike. There are a lot of ways. You can pick whichever one you want.

Finally, summarize the strategy pattern in one sentence:

All roads lead to Rome

Well, that’s all for today’s strategy patterns.

Looking forward to your likes and retweets.