There are feelings, there are dry goods, wechat search [three prince Ao bing] pay attention to the programmer who has a little bit of things.

This article has been included in GitHub github.com/JavaFamily, there are a line of large factory interview complete test sites, information and my series of articles.

Recently, a student was communicating with me about how to effectively avoid long if else judgments or switch condition judgments in code. The larger answer is to use design to circumvent this problem.

In design patterns, you can use the factory pattern or the strategy pattern to deal with this kind of problem. The factory pattern has been shared before, so you can review it if you are interested.

Previous articles in the Design Patterns series:

  • The singleton pattern
  • The factory pattern
  • The process engine
  • Builder model
  • The prototype pattern
  • Chain of Responsibility model
  • Observer model

So what’s the difference between factory mode and policy mode?

  • Factory pattern is a creation design pattern, which is mainly used to create different objects for different types to achieve decoupled objects.
  • The strategy pattern is a behavioral design pattern, which mainly makes corresponding behaviors for different strategies to achieve behavioral decouple

So let’s talk a little bit more about the strategy pattern how does it decouple behavior

The outline

define

What are strategic patterns? How does it work in principle?

Define a set of algorithms, encapsulate each algorithm, and make them interchangeable. Different strategies allow algorithms to change independently of the customers who use them. The above definition comes from the beauty of design patterns

Feeling a little abstract? Let’s take a look at a structure diagram

  • Strategy (Abstract Policy) : Abstracts the policy class and defines the policy execution entry
  • ConcreteStrategy: Implement an abstract strategy and an algorithm method
  • Context: Runs a specific policy class.

In this way, the structure is actually uncomplicated and similar to the state pattern.

So how does this code work?

For example, the concreteStrategy of cars is like different strategies: the driver chooses several gears, and the car moves forward at a certain speed. The whole choice is in the hands of the driver.

public interface GearStrategy {

    // Define policy execution methods
    void algorithm(String param);
}
Copy the code

First, define the abstract policy

This is in the form of an interface, and there’s another way to write it in the abstract method abstract and the same thing. Specific to see everyone’s choice.

public abstract class GearStrategyAbstract {
 // Define policy execution methods
 abstract void algorithm(String param);
}
Copy the code
public class GearStrategyOne implements GearStrategy {

    @Override
    public void algorithm(String param) {
        System.out.println("Current gear"+ param); }}Copy the code

Secondly, define specific stall strategy and realize algorithm method.

public class Context {
		// Cache all policies, currently stateless, can share policy class objects
    private static final Map<String, GearStrategy> strategies = new HashMap<>();

    // The first way
    static {
        strategies.put("one".new GearStrategyOne());
    }

    public static GearStrategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        return strategies.get(type);
    }

    // The second way
    public static GearStrategy getStrategySecond(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        if (type.equals("one")) {
            return new GearStrategyOne();
        }
        return null;
    }


    public static void main(String[] args) {
        // Test results
        GearStrategy strategyOne = Context.getStrategy("one");
        strategyOne.algorithm("1" ");
         // Result: current gear 1
        GearStrategy strategyTwo = Context.getStrategySecond("one");
        strategyTwo.algorithm("1" ");
        // Result: current gear 1}}Copy the code

And then finally the implementation runtime Context, you can define it as StrategyFactory, but it’s all the same thing.

In the test demo of the main method, you can see that different policies can be implemented with different types of type. This is the main idea of the policy pattern.

There are two ways to write Context:

  • The first maintains a Map container of strategies. In this way, it is necessary to determine whether each strategy can be shared and used only as an implementation of the algorithm.
  • The second option is to go directly through the stateful class, one new policy class object at a time based on type new. This needs to be judged according to the actual business scenario.

Application of framework

The policy pattern is also present in a very common place in the framework, and I’m sure you’ve all used it.

That’s ThreadPoolExecutor in the JDK

The first is to define a thread pool like this, which implements the exception policy for the thread pool.

The thread pool exception policy is based on the idea of the policy pattern.

RejectedExecutionHandler is an abstract exception policy interface in the source code, and it also has four rejection policies. The diagram is as follows:

This is reflected in the framework, according to their own business scenarios, reasonable selection of thread pool exception strategy.

Examples of Business Transformation

In real business scenarios, the policy pattern is also widely used.

Sharing goods in social e-commerce is a very important link. Suppose that we need to realize a picture sharing function, such as single goods, multiple goods, order, venue, invitation, small program link and so on.

Use an if else statement to make a normal business code judgment for the flow diagram, as shown below:

public class SingleItemShare {
    / / a single commodity
    public void algorithm(String param) {
        System.out.println("Currently shared image is"+ param); }}public class MultiItemShare {
    / / goods
    public void algorithm(String param) {
        System.out.println("Currently shared image is"+ param); }}public class OrderItemShare {
    / / order
    public void algorithm(String param) {
        System.out.println("Currently shared image is"+ param); }}public class ShareFactory {

    public static void main(String[] args) throws Exception {
        Integer shareType = 1;
       // Test the business logic
        if (shareType.equals(ShareType.SINGLE.getCode())) {
            SingleItemShare singleItemShare = new SingleItemShare();
            singleItemShare.algorithm("Single commodity");
        } else if (shareType.equals(ShareType.MULTI.getCode())) {
            MultiItemShare multiItemShare = new MultiItemShare();
            multiItemShare.algorithm("Multi-commodity");
        } else if (shareType.equals(ShareType.ORDER.getCode())) {
            OrderItemShare orderItemShare = new OrderItemShare();
            orderItemShare.algorithm("Order");
        } else {
            throw new Exception("Unknown share type");
        }
        / /... Omit more sharing scenarios
    }

    enum ShareType {
        SINGLE(1."Single commodity"),
        MULTI(2."Multi-commodity"),
        ORDER(3."Order");
        /**
         * 场景对应的编码
         */
        private Integer code;
        /** * Service scenario */
        private String desc;
        ShareType(Integer code, String desc) {
            this.code = code;
            this.desc = desc;
        }
        public Integer getCode(a) {
            return code;
        }
       // omit the get set method}}Copy the code

Here you can see that every time you add a new share type, you need to add an if else judgment, and when you have a dozen or so scenarios the code as a whole is very long and not very comfortable to look at.

Let’s take a look at refactoring using the policy pattern:

public interface ShareStrategy {
    // Define the sharing policy execution method
    void shareAlgorithm(String param);
}

public class OrderItemShare implements ShareStrategy {
    @Override
    public void shareAlgorithm(String param) {
        System.out.println("Currently shared image is"+ param); }}// Omit the MultiItemShare and SingleItemShare policies

// Share factory
public class ShareFactory {
		// Define policy enumeration
    enum ShareType {
        SINGLE("single"."Single commodity"),
        MULTI("multi"."Multi-commodity"),
        ORDER("order"."Order");
        // The encoding of the scene
        private String code;
       
        // Service scenario description
        private String desc;
        ShareType(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }
        public String getCode(a) {
            return code;
        }
       // omit the get set method
    }
		// Define the policy map cache
    private static final Map<String, ShareStrategy> shareStrategies = new       HashMap<>();
    static {
        shareStrategies.put("order".new OrderItemShare());
        shareStrategies.put("single".new SingleItemShare());
        shareStrategies.put("multi".new MultiItemShare());
    }
    // Get the specified policy
    public static ShareStrategy getShareStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        return shareStrategies.get(type);
    }
	
    public static void main(String[] args) {
        / / the demo test
        String shareType = "order";
        ShareStrategy shareStrategy = ShareFactory.getShareStrategy(shareType);
        shareStrategy.shareAlgorithm("order");
        // The current shared image is order}}Copy the code

Here the strategic model has been transformed. On the client side, you don’t see much if else judgment, just need to pass in the corresponding policy mode, here we maintain a policy cache map, when the direct call ShareFactory to get the policy class object directly from the other type.

This is the idea of behavioral uncoupling. It also avoids long if else judgments.

Advantages:

  • The algorithm strategy can be switched freely
  • Good scalability, add a policy, only need to add a class

Disadvantages:

  • The number of policy classes is large
  • You need to maintain a policy enumeration to let others know which policies you currently have

conclusion

So that’s it. The whole thing is actually relatively simple. We still need to learn the idea of each design mode. Don’t design your code for design patterns, either.

I’m Aobing, the more you know, the more you don’t know, thank you for your talent: likes, favorites and comments, we’ll see you next time!


This article is constantly updated. You can search “Santaizi Aobing” on wechat and read it for the first time. Reply [Information] There are the interview materials and resume templates for first-line big factories prepared by me.