The Alibaba developer manual only states that more than three layers of if-else logic can be implemented using strategy mode, but it doesn’t tell you how. The following is a general implementation.

implementation

Demand background

When making order prescription judgment, different operations should be done according to the type of order, which mainly includes four types at present:

  1. All push real-time order, corresponding to the enumeration object NORMAL_CANCELORDER
  2. Full push booking, corresponding to the enumeration object BOOK_CANCELORDER
  3. XUANTUI_CANCELORDER is used to push instant orders
  4. Select push reservation, corresponding to the enumeration object BOOK_XUANTUI_CANCELORDER

Define policy interfaces

Public enum TimerJudgeBizTypeEnum {NORMAL_CANCELORDER(1, "BOOK_CANCELORDER"), XUANTUI_CANCELORDER(3, "Push instant order ") and BOOK_XUANTUI_CANCELORDER(4," Push order "); private int code; private String desc; TimerJudgeBizTypeEnum(int code, String desc){ this.code = code; this.desc = desc; }}Copy the code
public interface TimerJudgeService {

    boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum);

    Response<T> getTimerJudge(Long orderId);

}
Copy the code

Defines the interface to the policy, including two methods:

  • IsMatched () is used to get the type of policy matched;
  • GetTimerJudge () is used to handle specific policy logic

Second, the concrete policy implementation class

Business logic processing of full push instant order:

@Service public class NormalCancelOrderJudgeTimerHandler implements TimerJudgeService { @Override public boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum) { return TimerJudgeBizTypeEnum.NORMAL_CANCELORDER.equals(bizTypeEnum); } @override public Response<T> getTimerJudge(Long orderId) {system.out.println ("... ); Return response. success(" return result "); }}Copy the code

Business logic processing of full push order:

@Service public class BookCancelOrderJudgeTimerHandler implements TimerJudgeService { @Override public boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum) { return TimerJudgeBizTypeEnum.BOOK_CANCELORDER.equals(bizTypeEnum); } @override public Response<T> getTimerJudge(Long orderId) {system.out.println ("... ); Return response. success(" return result "); }}Copy the code

The other two scenarios are similar

Create manager class

@Service
public class TimerJudgeManager implements ApplicationContextAware, InitializingBean {

    private ApplicationContext applicationContext;

    private List<TimerJudgeService> handlers = new ArrayList<>();
    
     public TimerJudgeService doGetHandle(TimerJudgeBizTypeEnum bizTypeEnum) {
        for (TimerJudgeService handler : handlers) {
            if (handler.isMatched(bizTypeEnum)) {
                return handler;
            }
        }
        return null;
    }

    @Override
    public void afterPropertiesSet() {

        for (TimerJudgeService handle : applicationContext.getBeansOfType(TimerJudgeService.class).values()) {
            handlers.add(handle);
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

Copy the code

4. Test classes

@Service public class TimerJudgeTest { @Autowired private TimerJudgeManager timerJudgeManager; public Response<T> test(TimerJudgeBizTypeEnum bizTypeEnum) { TimerJudgeService timerJudgeService = doGetHandle(bizTypeEnum); System.out.println(" return result "+ timerJudgeService); }}Copy the code

You can see that by having the TimerJudgeManager implement the ApplicationContextAware and InitializingBean interfaces, The afterPropertiesSet method then automatically registers all policy implementation classes into the Handlers hashMap based on Spring container startup. Then, specific policy implementation classes can be obtained by using doGetHandle method directly according to different business scenarios. To sum up, TimerJudgeManager is only responsible for obtaining the corresponding handler implementation class, and each handler implementation class is only responsible for implementing their own business logic, achieving the effect of “high cohesion and low coupling”. And when you need to add a policy class, you only need to implement the interface.

The advantages and disadvantages

advantages

  • Avoid a large number of if-else statements resulting in high coupling, bloated code, high maintenance costs;
  • Follow the open and close principle to achieve code decoupling. When a policy scenario is added, only one implementation class is added, which is very scalable and complies with the single responsibility principle for each implementation class.

Disadvantages:

  • The client must know all the policy classes, and then pass in the corresponding policy type when calling.

Usage scenarios

  • The specific policy implementation details are hidden from the client, completely independent of each other;
  • Multiple implementation classes are only different in business details, and the specific classes to be executed must be dynamically selected at runtime.