Learning and Understanding of Strategic Patterns in Design Patterns

Keywords: Java less

The strategy pattern belongs to the behavior pattern of the object. The intention is to encapsulate each algorithm into a separate class with a common interface for a set of algorithms, so that they can be replaced by each other. The policy pattern enables the algorithm to change without affecting the client.

Recently, the project needs to add a function of charging according to the inspection equipment. At first, I wrote it directly in a class for the sake of saving time.

 1 /**
 2  * Equipment Charge Category
 3  * Elevators charge a certain proportion according to the number of floors
 4  * The crane charges a certain proportion according to different lifting weights.
 5  * @author ko
 6  *
 7  */
 8 public class DeviceCharge {
 9 
10     private String deviceType;// Equipment type
11     private String ywjf;// Elevator organic room inorganic room
12     private int cs;// Elevator level
13     private int edqzl;// Crane rated lifting weight(t)
14     private int synx;// service life 
15     
16     public BigDecimal calCost(){
17         
18         BigDecimal decimal = null;
19         
20         if (deviceType.equals("LIFT")) {// Elevator.
21             if (ywjf.equals("yjf")) {// Computer room
22                 if (cs <= 5) {
23                     decimal = new BigDecimal(200);
24                 }else if (cs > 5 && cs <= 15) {
25                     decimal = new BigDecimal(200+(cs-5)*0.05);
26                 }else{
27                     decimal = new BigDecimal(200+(cs-5)*0.1);
28                 }
29             }else{// Inorganic room
30                 if (cs <= 5) {
31                     decimal = new BigDecimal(180);
32                 }else if (cs > 5 && cs <= 15) {
33                     decimal = new BigDecimal(180+(cs-5)*0.05);
34                 }else{
35                     decimal = new BigDecimal(180+(cs-5)*0.1);
36                 }
37             }
38         }else if (deviceType.equals("CRANE")) {// Crane
39             if (edqzl <= 3) {
40                 decimal = new BigDecimal(1000);
41             }else if (edqzl > 3 && edqzl <= 15) {
42                 decimal = new BigDecimal(1000+(edqzl-3)*0.07);
43             }else{
44                 decimal = new BigDecimal(1000+(edqzl-3)*0.13);
45             }
46         }else{
47             decimal = new BigDecimal(100);
48         }
49         
50         if (synx > 20) {// No matter what kind of equipment, it will cost 5 more if it is used for more than 20 years.%
51             return decimal.add(decimal.multiply(new BigDecimal(0.05)));
52         }else{
53             return decimal;
54         }
55     }
56     
57 }

It can be found that the charging algorithm is very complex. When new algorithms need to be added in the future, it is very difficult to maintain, and so many if-else are extremely confusing, and there is a certain amount of code duplication. It is now found that policy patterns have related advantages:

(1) The policy pattern provides a way to manage the related algorithmic families. The hierarchical structure of policy classes defines an algorithm or behavior family. Proper use of inheritance can move common code into the parent class, thus avoiding code duplication.

(2) The use of policy patterns can avoid the use of multiple conditional (if-else) statements. Multiple conditional statements are not easy to maintain. It combines the logic of which algorithm or behavior to be adopted with the logic of algorithm or behavior. It is more primitive and backward than the method of inheritance.

So I decided to use the strategy model to write:

First, we abstract an AbstractDeviceCharge class to facilitate the inheritance of different algorithms. This way, we write a getOverTwentyCost () method, which is not an abstract method. On the contrary, if each algorithm does not need to refine the common method, we can write an interface directly on this side.

 1 /**
 2  * Abstract equipment charge class
 3  * Elevators charge a certain proportion according to the number of floors
 4  * The crane charges a certain proportion according to different lifting weights.
 5  * @author ko
 6  *
 7  */
 8 public abstract class AbstractDeviceCharge {
 9 
10     
11     /**
12      * On the basis of the original price, if it exceeds 20 years, it will be charged 5% more.
13      * @param decimal 
14      * @return
15      */
16     public BigDecimal getOverTwentyCost(BigDecimal decimal){
17         return decimal.add(decimal.multiply(new BigDecimal(0.05)));
18     }
19     
20     /**
21      * Computation cost
22      * @return
23      */
24     public abstract BigDecimal calCost();
25 }

Write an elevator abstract class and inherit the AbstractDeviceCharge class:

1 /**
2  * Abstract elevator charge class
3  * @author ko
4  *
5  */
6 public abstract class LiftCharge extends AbstractDeviceCharge {
7     
8 }

There are organic rooms and inorganic rooms under the elevator.

 1 /**
 2  * Elevator Charge Class in Organic Room
 3  * @author ko
 4  *
 5  */
 6 public abstract class YjfLiftCharge extends LiftCharge {
 7 
 8     protected BigDecimal basicDecimal;// Basic Charge Standard for Elevators in Organic Rooms
 9 
10     public YjfLiftCharge(BigDecimal basicDecimal){
11         this.basicDecimal = basicDecimal;
12     }
13 }

The charging algorithm for elevators with different floors in an organic room:

 1 /**
 2  * Elevators with floors less than or equal to 5 in an organic room
 3  * @author ko
 4  *
 5  */
 6 public class YjfOneLiftCharge extends YjfLiftCharge {
 7 
 8     public YjfOneLiftCharge(BigDecimal baseDecimal) {
 9         super(baseDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal;
15     }
16 
17 }
 1 /**
 2  * Elevators with floors less than or equal to 15 or more than 5% are charged 5%.
 3  * @author ko
 4  *
 5  */
 6 public class YjfTwoLiftCharge extends YjfLiftCharge {
 7 
 8     public YjfTwoLiftCharge(BigDecimal baseDecimal) {
 9         super(baseDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal.add(basicDecimal.multiply(new BigDecimal(0.05)));
15     }
16     
17 }
 1 /**
 2  * Elevators with more than 15 floors in organic rooms are charged 10%.
 3  * @author ko
 4  *
 5  */
 6 public class YjfThreeLiftCharge extends YjfLiftCharge {
 7 
 8     public YjfThreeLiftCharge(BigDecimal baseDecimal) {
 9         super(baseDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal.add(basicDecimal.multiply(new BigDecimal(0.1)));
15     }
16     
17 }

The same is true for cranes. Because there is no specific type of crane under the crane (in fact, there are all kinds of cranes, the default crane type is the same here for the sake of saving time), the basic fee is passed in when the crane is initialized directly.

 1 /**
 2  * Abstract crane toll class
 3  * @author ko
 4  *
 5  */
 6 public abstract class CraneCharge extends AbstractDeviceCharge {
 7     
 8     protected BigDecimal basicDecimal;
 9     
10     public CraneCharge(BigDecimal basicDecimal){
11         this.basicDecimal = basicDecimal;
12     }
13 }

Charging algorithms for cranes with different lifting weights:

 1 /**
 2  * Crane with rated lifting weight less than or equal to 3
 3  * @author ko
 4  *
 5  */
 6 public class CraneOneCharge extends CraneCharge {
 7 
 8     public CraneOneCharge(BigDecimal basicDecimal) {
 9         super(basicDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal;
15     }
16 
17 }
 1 /**
 2  * Cranes with rated lifting weight greater than 3 and less than or equal to 7 are charged 10%.
 3  * @author ko
 4  *
 5  */
 6 public class CraneTwoCharge extends CraneCharge {
 7 
 8     public CraneTwoCharge(BigDecimal basicDecimal) {
 9         super(basicDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal.add(basicDecimal.multiply(new BigDecimal(0.1)));
15     }
16 
17 }
 1 /**
 2  * Cranes with rated lifting weight greater than 7 will be charged 20%.
 3  * @author ko
 4  *
 5  */
 6 public class CraneThreeCharge extends CraneCharge {
 7 
 8     public CraneThreeCharge(BigDecimal basicDecimal) {
 9         super(basicDecimal);
10     }
11 
12     @Override
13     public BigDecimal calCost() {
14         return basicDecimal.add(basicDecimal.multiply(new BigDecimal(0.2)));
15     }
16 
17 }

Everything is ready. Here's the client call.

 1 /**
 2  * Client
 3  * @author ko
 4  *
 5  */
 6 public class Client {
 7 
 8     // Elevator Basic Charge Standard (the actual project can be configured in the configuration file, so that even if there are changes, there is no need to change the code)
 9     public static final BigDecimal LIFT_BASE_DECIMAL = new BigDecimal(200);
10     
11     // Crane Basic Charge Standard (the actual project can be configured in the configuration file, so that even if there are changes do not need to change the code)
12     public static final BigDecimal CRANE_BASE_DECIMAL = new BigDecimal(500);
13     
14     public static void main(String[] args) {
15         
16         YjfLiftCharge yjfOneLift = new YjfOneLiftCharge(LIFT_BASE_DECIMAL);
17         System.out.println("Elevator charges for organic rooms with floors less than 5:"+yjfOneLift.calCost());
18         
19         CraneCharge overTwentyTwoCrane = new CraneTwoCharge(CRANE_BASE_DECIMAL);
20         System.out.println("Over 20 years, crane charges with rated load greater than or equal to 3 or less than 7:"+overTwentyTwoCrane.getOverTwentyCost(overTwentyTwoCrane.calCost()));
21         
22     }
23 }

After the above ups and downs, we will have a clearer understanding of the strategic model:

The Focus of Strategic Model

The focus of policy mode is not how to implement algorithms, but how to organize and call these algorithms, so that the program structure is more flexible and has better maintainability and expansibility.

Equality of algorithms

One of the great characteristics of the strategy model is the equality of each strategy algorithm. For a series of specific strategies and algorithms, we all have the same status. Because of this equality, we can realize that the algorithms can be replaced each other. All the strategy algorithms are also independent in implementation and are independent of each other.

So we can describe this series of policy algorithms as follows: policy algorithms are different implementations of the same behavior.

Uniqueness of Runtime Policy

During the running period, the policy pattern can only use one specific policy to implement objects at each time. Although it can dynamically switch among different policy implementations, it can only use one at the same time.

Public behavior

It is common to see that all specific strategy classes have some common behavior. At this point, these public behaviors should be placed in the common abstract policy role AbstractDeviceCharge class. Of course, Abstract policy roles must be implemented using Java Abstract classes, not interfaces.

This is also a typical standard way to centralize code above the inheritance hierarchy.

At the same time, we can find some shortcomings of the strategy model:

(1) The client must know all the policy classes and decide which one to use. This means that the client must understand the differences between these algorithms in order to select the appropriate algorithm class in time. In other words, the policy pattern only applies when the client knows the algorithm or behavior.

(2) Since the policy pattern encapsulates each specific policy implementation as a class separately, if there are many alternative strategies, the number of objects will be large, which means that many classes will be written.

Posted by lookee on Mon, 08 Apr 2019 18:27:31 -0700