Use policy patterns elegantly with the power of Spring
What ispageThe strategy pattern
Strategy Pattern tutorial: Strategy Pattern
Definition: An object that has a behavior that can be implemented by different algorithms in different scenarios. In the case of similar algorithms, if… else… The resulting complexity and difficult to maintain. Key code: implement the same interface.
Application scenarios
public Integer getResult(Integer num1, Integer num2, OperationTypeEnum typeEnum) {
// Determine the operation type
if (OperationTypeEnum.ADD == typeEnum) {
/ / add
return num1 + num2;
} else if (OperationTypeEnum.SUBTRACT == typeEnum) {
/ / by subtracting
return num1 - num2;
} else if (OperationTypeEnum.MULTIPLY == typeEnum) {
/ / multiplied
return num1 * num2;
}
throw new RuntimeException("No corresponding operation type");
}
Copy the code
Scenario: There are two Integer numbers num1 and num2, and the corresponding adding, subtracting, and multiplying logic (algorithm implementation) is performed based on the operation type (scenario) of the input parameters. In this way, our application scenario corresponds to the policy pattern definition described above. Disadvantages: With the complexity of implementation logic, and the expansion of operation types, if… else… Logical blocks become more and more bulky and difficult to maintain.
Elegant strategy pattern
The rookie tutorial implements a classic strategy mode solution for the above scenario. This article, however, aims to elegantly implement the policy pattern by leveraging Spring’s @AutoWired annotation to directly inject the collection types of classes.
- Add, subtract, and multiply to implement the same interface
OperationService
The same method ofdoOperation()
.
public interface OperationService {
/** * Perform the operation **@param num1
* @param num2
* @return* /
Integer doOperation(Integer num1, Integer num2);
}
Copy the code
@Service("addOperationServiceImpl")
public class AddOperationServiceImpl implements OperationService {
/** * Perform the add operation **@param num1
* @param num2
* @return* /
@Override
public Integer doOperation(Integer num1, Integer num2) {
returnnum1 + num2; }}Copy the code
@Service("subtractOperationServiceImpl")
public class SubtractOperationServiceImpl implements OperationService {
/** * Perform the subtraction operation **@param num1
* @param num2
* @return* /
@Override
public Integer doOperation(Integer num1, Integer num2) {
returnnum1 - num2; }}Copy the code
@Service("multiplyOperationServiceImpl")
public class MultiplyOperationServiceImpl implements OperationService {
/** * perform the multiplication operation **@param num1
* @param num2
* @return* /
@Override
public Integer doOperation(Integer num1, Integer num2) {
returnnum1 * num2; }}Copy the code
- Three kinds of operationtypeAnd operatingImplement the name of the class Bean, maintain to enumeration
OperationTypeEnum
Is used as a dictionary.
public enum OperationTypeEnum {
/** * add */
ADD(1."Together"."addOperationServiceImpl"),
/** ** subtracts */
SUBTRACT(2."Subtraction"."subtractOperationServiceImpl"),
/** ** ** /
MULTIPLY(3."Multiply"."multiplyOperationServiceImpl");
/** * unique encoding */
private Integer code;
/** * description */
private String desc;
/** * The name of the corresponding policy pattern implementation class Bean */
private String strategyBeanName;
/* Constructor */
/* getter & setter */
}
Copy the code
As in the code above, the name of the operation implementation class Bean, identified in the @Service annotation parentheses above each implementation class, is mapped to the operation type through the enumeration OperationTypeEnum.
- Calculate the operation policy interface
CalculateOperationStrategy
There’s only one waycalculate()
. I don’t need to talk about interfaces anymore, but just look at the implementation classes.
@Service("calculateOperationStrategy")
public class CalculateOperationStrategyImpl implements CalculateOperationStrategy {
/** * 'Inject all beans of type OperationService into a Map * whose key is Bean name */
@Autowired
private Map<String, OperationService> operationServiceMap;
/** * count **@param num1
* @param num2
* @param type
* @return* /
@Override
public Integer calculate(Integer num1, Integer num2, OperationTypeEnum type) {
// The name of the policy pattern implementation class Bean corresponding to this operation type
String strategyBeanName = type.getStrategyBeanName();
if(operationServiceMap.get(strategyBeanName) ! =null) {
// Execute the doOperation method of the corresponding policy pattern implementation class
return operationServiceMap.get(strategyBeanName).doOperation(num1, num2);
} else {
throw new RuntimeException("No corresponding operation type"); }}Copy the code
- We’re through
@Autowired
The interface directly sets all types toOperationService
Is injected into a Map of the Beankey 为 The Bean’s name. See my last article for a detailed implementation of this step:[Spring] @autoWired A deep anatomy of the collection types of injected classes. - We just know the enumeration of the operation type passed in
OperationTypeEnum
So we can use this name as the key, get the implementation class of the corresponding operation type from the Map, and finally call the implementation class of the corresponding operation type directlydoOperation()
Methods.
- Finally, the test class
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PpValidatorApplication.class)
public class CalculateOperationStrategyTest {
@Autowired
private CalculateOperationStrategy calculateOperationStrategy;
@Test
public void testCalculate(a) {
Integer num1 = 66;
Integer num2 = 6;
System.out.println("Calculation method:"
+ OperationTypeEnum.ADD.getDesc()
+ " ---> 计算结果:"
+ calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.ADD));
System.out.println("Calculation method:"
+ OperationTypeEnum.SUBTRACT.getDesc()
+ " ---> 计算结果:"
+ calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.SUBTRACT));
System.out.println("Calculation method:"
+ OperationTypeEnum.MULTIPLY.getDesc()
+ " ---> 计算结果:"+ calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.MULTIPLY)); }}Copy the code
The result is as follows
Calculation method: add --> result: 72 Calculation method: subtract --> result: 60 Calculation method: multiply --> result: 396Copy the code
!!!!!!!!! Perfect!!
conclusion
- Policy patterns can perform implementation logic corresponding to the type in the program context. Subsequent modification and replacement are very convenient.
- The policy pattern can be elegantly implemented with Spring’s @AutoWired annotation, which allows direct injection of class collection types. [Spring] @autowired Injection class set type deep anatomy.
- Each implementation class only needs to maintain the contents of its own class
doOperation()
Method can.- To extend the type, simply add an implementation class, the implementation
OperationService
Interface, and maintains the name and type of the implementation class Bean into the dictionary enumerationOperationTypeEnum
In the.
HelloLittleRain: A simple book to share