demand

Here is a fictitious business requirement to make it easy to understand. Suppose you have an order system in which one of the functions is to make different processing based on different types of orders.

Order Entity:

The service interface:

Traditional implementation

Write a bunch of if else based on the order type:

Policy pattern implementation

With the policy pattern, only two lines are needed to implement the business logic:

You can see that HandlerContext is injected into the above method, which is a processor context that holds different business handlers, as explained below. We took an abstract processor, AbstractHandler, and invoked its methods to implement the business logic.

You can now see that most of our business logic is implemented in processors, so there should be as many processors as there are order types. Later, when the requirements changed and the order type was added, all we needed to do was add the corresponding processor, and the OrderServiceV2Impl was left unchanged.

Let’s look at the business processor first:

First, each processor must be added to the Spring container, hence the @Component annotation. Second, we need to add a custom annotation @HandlerType that identifies the order type of the processor. Finally, we need to inherit AbstractHandler to implement our own business logic.

Custom annotation @handlerType:

Abstract processor AbstractHandler:

It’s easy to customize annotations and abstract handlers, so how do you register your handlers with the Spring container?

The specific ideas are as follows:

1. Scan the class marked with @handlerType in the specified package;

2. Store the type value in the annotation as key and the corresponding class as value in the Map;

3. Initialize HandlerContext as a constructor parameter, and register it with the Spring container.

We encapsulate the core functions in the HandlerProcessor class to complete the above functions.

HandlerProcessor:

ClassScanner: scans the source code of tool classes

HandlerProcessor needs to implement BeanFactoryPostProcessor, which registers custom beans into the container before Spring processes them.

Now that the core work is done, let’s see how HandlerContext gets its handler:

HandlerContext:

BeanTool: Gets the bean utility class

The #getInstance method gets the corresponding class based on the type, and then gets the bean registered in Spring based on the class type.

Finally, note that HandlerProcessor and BeanTool must be scanned or explicitly registered via @bean to be effective at project startup.

conclusion

The policy pattern simplifies complex if and else code for easy maintenance, while custom annotations and self-registration make it easier to respond to changing requirements. This article is just a general idea, but there are many details that can be changed flexibly, such as using enumerated types or static constants as the types of orders. I’m sure you can think of more and better methods.

Focus on a walk, live to 999 focus on the home page there are surprises

See the full example code: handler_demo

Read more: www.ciphermagic.cn reprinted from: juejin.cn/post/684490…