20 Behavioral Pattern-Strategic Pattern

1 Overview of Strategy Pattern

The original definition of strategy pattern is to define a series of algorithms, encapsulate each algorithm, and make them interchangeable. The Strategy pattern allows an algorithm to vary independently of the client using it.

2 Principles of Strategy Pattern

3 Strategy pattern implementation

The essence of the strategy mode is to use the Context class as the central control unit to schedule and distribute different strategies.

//Abstract strategy class
public interface Strategy {<!-- -->
void algorithm();
}
/**
 * Specific strategies
 **/
public class ConcreteStrategyA implements Strategy {<!-- -->

    @Override
    public void algorithm() {<!-- -->
        System.out.println("Execution Policy A");
    }
}
public class ConcreteStrategyB implements Strategy {<!-- -->

    @Override
    public void algorithm() {<!-- -->
        System.out.println("Execution Policy B");
    }
}
/**
 * Context class: The essence of the strategy pattern is to use the Context class as the control unit.
 * Schedule and allocate different strategies
 **/
public class Context {<!-- -->

    //Maintain a reference to an abstract strategy
    private Strategy strategy;

    public Context(Strategy strategy) {<!-- -->
        this.strategy = strategy;
    }

    //Call the algorithm in the strategy class
    public void algorithm(){<!-- -->
        strategy.algorithm();
    }
}
public class Client {<!-- -->

    public static void main(String[] args) {<!-- -->

        Strategy strategyB= new ConcreteStrategyB();
        Context context = new Context(strategyB);

        context.algorithm();
    }
}

1) Not using design patterns
/**
 *Receipt information
 **/
public class Receipt {<!-- -->

    private String message; //Receipt content
    private String type; //Receipt type: MT1101, MT2101, MT4101, MT8104

    public Receipt() {<!-- -->
    }

    public Receipt(String message, String type) {<!-- -->
        this.message = message;
        this.type = type;
    }

    public String getMessage() {<!-- -->
        return message;
    }

    public void setMessage(String message) {<!-- -->
        this.message = message;
    }

    public String getType() {<!-- -->
        return type;
    }

    public void setType(String type) {<!-- -->
        this.type = type;
    }
}
/**
 *Receipt information
 **/
public class Receipt {<!-- -->

    private String message; //Receipt content
    private String type; //Receipt type: MT1101, MT2101, MT4101, MT8104

    public Receipt() {<!-- -->
    }

    public Receipt(String message, String type) {<!-- -->
        this.message = message;
        this.type = type;
    }

    public String getMessage() {<!-- -->
        return message;
    }

    public void setMessage(String message) {<!-- -->
        this.message = message;
    }

    public String getType() {<!-- -->
        return type;
    }

    public void setType(String type) {<!-- -->
        this.type = type;
    }
}
public class Client {<!-- -->

    public static void main(String[] args) {<!-- -->

        List<Receipt> receiptList = ReceiptBuilder.getReceiptList();

        //Receipt type: MT1101, MT2101, MT4101, MT8104
        for (Receipt receipt : receiptList) {<!-- -->
            if("MT1011".equals(receipt.getType())){<!-- -->
                System.out.println("Received receipt information of MT1011");
                System.out.println("Parse the receipt content");
                System.out.println("Execute business logic A...");
            }else if("MT2101".equals(receipt.getType())){<!-- -->
                System.out.println("Received receipt information from MT2101");
                System.out.println("Parse the receipt content");
                System.out.println("Execute business logic B...");
            }else if("MT4101".equals(receipt.getType())){<!-- -->
                System.out.println("Received receipt information of MT4101");
                System.out.println("Parse the receipt content");
                System.out.println("Execute business logic C...");
            }else if("MT8104".equals(receipt.getType())){<!-- -->
                System.out.println("Received receipt information from MT8104");
                System.out.println("Parse the receipt content");
                System.out.println("Execute business logic D......");
            }
            //......
        }
    }
}
2) Use strategy mode for optimization

Through the strategy mode, the business logic of all if-else branches is extracted into various strategy classes, allowing the client to rely on
Rely on the policy interface to ensure that changes in specific policy classes do not affect the client.

/**
 *Receipt processing strategy interface
 **/
public interface ReceiptHandleStrategy {<!-- -->
    void handleReceipt(Receipt receipt);
}

Specific strategy class

/**
 * Specific strategies
 **/
public class MT1101ReceiptHandleStrategy implements ReceiptHandleStrategy {<!-- -->

    @Override
    public void handleReceipt(Receipt receipt) {<!-- -->
        System.out.println("Parse message MT1101: " + receipt.getMessage());
    }
}
public class MT2101ReceiptHandleStrategy implements ReceiptHandleStrategy {<!-- -->

    @Override
    public void handleReceipt(Receipt receipt) {<!-- -->
        System.out.println("Parse message MT2101: " + receipt.getMessage());
    }
}

Strategy context class (holder of the strategy interface)

/**
 * Context class, holds the strategy interface and decides which specific strategy class to execute
 **/
public class ReceiptStrategyContext {<!-- -->

    private ReceiptHandleStrategy receiptHandleStrategy;

    public void setReceiptHandleStrategy(ReceiptHandleStrategy receiptHandleStrategy) {<!-- -->
        this.receiptHandleStrategy = receiptHandleStrategy;
    }

    //Call the method in the strategy class
    public void handleReceipt(Receipt receipt){<!-- -->
        if(receipt != null){<!-- -->
            receiptHandleStrategy.handleReceipt(receipt);
        }
    }
}

strategy factory

/**
 * Strategy factory class
 **/
public class ReceiptHandleStrategyFactory {<!-- -->

    public ReceiptHandleStrategyFactory() {<!-- -->
    }

    //Use Map collection to store policy information and completely eliminate if...else
    private static Map<String,ReceiptHandleStrategy> strategyMap;

    //Initialize the specific strategy and save it to the map collection
    public static void init(){<!-- -->
        strategyMap = new HashMap<>();
// strategyMap.put("MT1101",new MT1101ReceiptHandleStrategy());
// strategyMap.put("MT2101",new MT2101ReceiptHandleStrategy());
        try {<!-- -->
            SAXReader reader = new SAXReader();
            String file = "I:\MSB\msb_work\designpattern\msb-strategy-pattern-14\src\main\\resources\ \config.xml";

            Document document = reader.read(file);
            Node node = document.selectSingleNode("/confing/className");
            String className = node.getText();
            Class clazz = Class.forName(className);
            ReceiptHandleStrategy strategy = (ReceiptHandleStrategy) clazz.newInstance();
            strategyMap.put("MT1101",strategy);
        } catch (Exception e) {<!-- -->
            e.printStackTrace();
        }
    }

    //According to the receipt type, obtain the corresponding policy object
    public static ReceiptHandleStrategy getStrategy(String receiptType){<!-- -->
        return strategyMap.get(receiptType);
    }
}
public class Client {<!-- -->

    public static void main(String[] args) {<!-- -->

        //Simulate receipt
        List<Receipt> receiptList = ReceiptBuilder.getReceiptList();

        //Strategy context
        ReceiptStrategyContext context = new ReceiptStrategyContext();

        //The main work of the strategy pattern: decoupling the definition, creation, and use of the strategy.
        for (Receipt receipt : receiptList) {<!-- -->
            //Get strategy
            ReceiptHandleStrategyFactory.init();
            ReceiptHandleStrategy strategy = ReceiptHandleStrategyFactory.getStrategy(receipt.getType());
            //Set strategy
            context.setReceiptHandleStrategy(strategy);
            //Execution strategy
            context.handleReceipt(receipt);
        }

    }
}

After the above transformation, we have eliminated the if-else structure. Whenever a new receipt comes, just
To add a new receipt processing strategy and modify the Map in ReceiptHandleStrategyFactory
gather. If you want to make the program comply with the opening and closing principle, you need to adjust the acquisition method of the processing strategy in ReceiptHandleStrategyFactory, obtain all IReceiptHandleStrategy implementation classes under the specified package through reflection, and then put them in the dictionary Map.

5 Strategy Mode Summary