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.