Join the Code Farming technology sharing community

Policy mode. In actual project development, this pattern is also more common. It is most commonly used to avoid lengthy if-else or switch branch judgments. But it does more than that. It can also provide extension points for the framework, and so on, as the template pattern does. For the policy pattern. In this article we explain the principle and implementation of the policy pattern and how it can be used to avoid branching judgment logic. Later, I will use a specific example to explain in detail how the strategy pattern is used and what the real design intent is. Without further ado, let’s get to the point

The principle and implementation of policy pattern

Policy patterns can make changes to algorithms independent of the clients that use them (by client I mean the code that uses the algorithm). As we know, the factory pattern decouples the creation and use of objects, and the observer pattern decouples the observer and observed. The policy pattern is similar in that it decouples the definition, creation, and use of the policy. Read the following article to speed up your understanding of the strategy pattern

Design pattern behavior: StrategyPattern

Next, I’ll elaborate on the three parts of a complete strategy pattern.

Definition of policy

The definition of a policy class is relatively simple. It consists of a policy interface and a set of policy classes that implement the interface. Because all policy classes implement the same interface, client code is based on interface rather than implementation programming and has the flexibility to replace different policies. The sample code looks like this:

Policy creation

Because the policy pattern contains a set of policies, when using them, the type is used to determine which policy to create and use. To encapsulate the creation logic, we need to mask the creation details from the client code. We can take the logic for creating policies based on Type and put it in a factory class. The sample code is shown below

In general, if the policy class is stateless, contains no member variables, and is a pure algorithm implementation, such a policy object can be shared without the need to create a new policy object every time getStrategy() is called. In this case, we can use the factory class implementation above. We can create each policy object in advance, cache it in the factory class, and return it when we use it.

On the contrary, if the policy class is stateful and we want to get the newly created policy object from the factory method each time, rather than the cached and shareable policy object, according to the business scenario, we need to implement the policy factory class as follows.

Use of policy patterns

Now that we’ve talked about defining and creating policies, let’s look at using policies. We know that the policy pattern contains a set of alternative policies, so how does client code generally decide which policy to use? The most common is when the runtime dynamically determines which policy to use, and this is where the policy pattern is most typically used. By “runtime dynamics,” we mean that we don’t know which policy will be used in advance, but rather that we dynamically decide which policy to use during the running of the program based on uncertainties such as configuration, user input, computed results, and so on. Next, let’s use an example to explain.

From the code above, we can also see that “non-runtime dynamic determination,” which is used in the second Application, does not take advantage of the policy pattern. In this application scenario, the policy pattern actually degenerates into “object-oriented polymorphism” or “based on interfaces rather than implementing programming principles.”

How can you use policy patterns to avoid branching judgments

In fact, it is not only the policy mode that can remove the branching judgment logic, but also the state mode that we will cover later. Which pattern to use depends on the application scenario. The policy mode applies to the application scenario in which policies are used based on different types of dynamics. Let’s start with an example of how if-else or switch-case branch judgment logic is generated. The specific code is shown below. In this example, instead of using the policy pattern, we directly couple the definition, creation, and usage of the policy.

How do you remove the branching logic? That’s where the strategic model comes in. We refactor the above code using the policy pattern to design the discount policies for different types of orders into policy classes, with the factory class responsible for creating policy objects. The specific code is as follows:

The refactored code does not have if-else branch judgments. In fact, this is thanks to the policy factory class. In the factory class, we cache policies with a Map and get the corresponding policies directly from the Map based on type, avoiding if-else branching logic. Later, when we talk about using state patterns to avoid branching logic, we’ll see that they all follow the same pattern. In essence, the method is based on “table lookup”, which is based on type lookup (strategies in the code are tables) instead of branch judgment based on type. However, if the business scenario needs to create a different policy object each time, we will use a different implementation of the factory class. The specific code is as follows:

conclusion

The policy pattern defines a family of algorithm classes and encapsulates each algorithm individually so that they can be replaced with each other. Policy patterns can make changes to algorithms independent of the clients that use them (by client I mean the code that uses the algorithm). Policy patterns are used to decouple the definition, creation, and use of policies. In fact, a complete strategy pattern is made up of these three parts. The definition of a policy class is relatively simple. It consists of a policy interface and a set of policy classes that implement the interface. Policy creation is done by the factory class, encapsulating the details of policy creation. The policy pattern contains a set of policies to choose from, and there are two ways to determine how the client code chooses which policy to use: statically at compile time and dynamically at run time. Among them, “dynamic determination at runtime” is the most typical application scenario of policy pattern. In addition, we can remove if-else branch judgments through policy mode. In fact, this is thanks to the policy factory class, and more essentially, through “table lookup”, which looks up tables by type instead of branching by type.

Join the Code Farming technology sharing community