The of Java design patterns -- policy patterns

Posted by John Cartwright on Sat, 04 Dec 2021 04:29:42 +0100

1. What is the strategy model?

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Strategy Pattern: define a family of algorithm classes, encapsulate each algorithm separately, so that they can replace each other.

2. Policy pattern definition

① Context encapsulates roles

It is also called context role, which serves as a connecting link between the preceding and the following, shields the direct access of high-level modules to policies and algorithms, and encapsulates possible changes.

② Strategy Abstract policy role

The abstraction of a policy or algorithm family, usually an interface, defines the methods and attributes that each policy or algorithm must have.

③ Concrete strategy specific policy roles

Implement the operations in the abstract policy. This class contains specific algorithms.

3. Policy mode common code

public class Context {
    // Abstract strategy
    private Strategy strategy = null;
    // Constructor to set specific policies
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    // Encapsulated strategy and method
    public void doAnything(){
        this.strategy.doSomething();
    }
}
public interface Strategy {
    // Algorithm of policy mode
    public void doSomething();
}
public class ConcreteStrategy1 implements Strategy{
    @Override
    public void doSomething() {
        System.out.println("ConcreteStrategy1");
    }
}
public class ConcreteStrategy2 implements Strategy{
    @Override
    public void doSomething() {
        System.out.println("ConcreteStrategy2");
    }
}

Test:

public class StrategyClient {
    public static void main(String[] args) {
        // Declare a specific policy
        Strategy strategy = new ConcreteStrategy1();
        // Declare context object
        Context context = new Context(strategy);
        // Post encapsulation method
        context.doAnything();
    }
}

4. Rewrite if else with policy mode

Suppose we want to process an office file, which is divided into three types: docx, xlsx and pptx. They represent Word file, Excel file and PPT file respectively, which are parsed according to the file suffix.

4.1 conventional writing

public class OfficeHandler {

    public void handleFile(String filePath){
        if(filePath == null){
            return;
        }
        String fileExtension = getFileExtension(filePath);
        if(("docx").equals(fileExtension)){
            handlerDocx(filePath);
        }else if(("xlsx").equals(fileExtension)){
            handlerXlsx(filePath);
        }else if(("pptx").equals(fileExtension)){
            handlerPptx(filePath);
        }
    }

    public void handlerDocx(String filePath){
        System.out.println("handle docx file");
    }
    public void handlerXlsx(String filePath){
        System.out.println("handle xlsx file");
    }
    public void handlerPptx(String filePath){
        System.out.println("handle pptx file");
    }
    private static String getFileExtension(String filePath){
        // Resolve the file name to obtain the file extension, such as document. Docx, and return docx
        String fileExtension = filePath.substring(filePath.lastIndexOf(".")+1);
        return fileExtension;
    }
}

If the processing logic is all placed in one class, the whole class will be very large. Suppose we want to add a new type of processing. For example, for office files before version 2007, the suffixes are doc/xls/ppt respectively, we have to add else if logic, which violates the opening and closing principle. How to solve this problem? The answer is through the policy mode.

4.2 strategy mode rewriting

public interface OfficeHandlerStrategy {
    void handlerOffice(String filePath);
}
public class OfficeHandlerDocxStrategy implements OfficeHandlerStrategy {
    @Override
    public void handlerOffice(String filePath) {
        System.out.println("handle docx");
    }
}

//Omit the OfficeHandlerXlsxStrategy/OfficeHandlerPptxStrategy class

public class OfficeHandlerStrategyFactory {
    private static final Map<String,OfficeHandlerStrategy> map = new HashMap<>();
    static {
        map.put("docx",new OfficeHandlerDocxStrategy());
        map.put("xlsx",new OfficeHandlerXlsxStrategy());
        map.put("pptx",new OfficeHandlerPptxStrategy());
    }
    public static OfficeHandlerStrategy getStrategy(String type){
        return map.get(type);
    }
}

Test:

public class OfficeHandlerStrategyClient {
    public static void main(String[] args) {
        String filePath = "C://file/123.xlsx";
        String type = getFileExtension(filePath);
        OfficeHandlerStrategy strategy = OfficeHandlerStrategyFactory.getStrategy(type);
        strategy.handlerOffice(filePath);
    }

    private static String getFileExtension(String filePath){
        // Resolve the file name to obtain the file extension, such as document. Docx, and return docx
        String fileExtension = filePath.substring(filePath.lastIndexOf(".")+1);
        return fileExtension;
    }
}

4. Advantages of strategic mode

① The algorithm can be switched freely

This is defined by the policy pattern itself. As long as the abstract policy is implemented, it becomes a member of the policy family. It is encapsulated by encapsulating roles to ensure that "freely switchable" policies are provided externally.

② Avoid using multiple conditional judgments

Simplify multiple if else, or multiple switch case branches.

③ Good expansibility

To add a policy, you only need to implement one interface.

5. Policy mode application scenario

① Multiple classes have only slightly different scenarios in algorithm or behavior.

② Scenarios where the algorithm needs to be switched freely.

③ . scenarios that need to mask algorithm rules.