职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到结束。
定义一个抽象类AbstractHandler,提供一个对外方法handleRequest(),处理外部请求。抽象类分别有三个具体实现类,GuestHandler、CustomerHandler、MerchantHandler对应三种条件下的处理逻辑,如果不采用职责链设计模式,那么通常就是通过if...else...实现,if customer ... else if merchant ... else if guest ... else ...
职责链设计模式,当提交一个请求时,由第一个AbstractHandler实现类处理,如果满足条件则处理返回,否则移交给下一个AbstractHandler实现类处理,直至没有下一个。这样设计的好处符合开闭原则,每当新增一种条件,只需要增加一个AbstractHandler实现类,而不需要改动已有类,对拓展开放对修改封闭。
import com.tj.designpatterns.chofresb.model.HandlerRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractHandler { private static final Logger log = LoggerFactory.getLogger(AbstractHandler.class); private AbstractHandler next; public AbstractHandler getNext() { return next; } public void setNext(AbstractHandler next) { this.next = next; } public void handleRequest(HandlerRequest request) { if (isHit(request)) { this.handle(request); return; } if (this.next != null) { this.next.handleRequest(request); } else { log.warn("no handler execute, request: {}", request); } } protected abstract boolean isHit(HandlerRequest request); protected abstract void handle(HandlerRequest request); }
如果是hit一个handler类后,需要继续判断其他的handler类,满足hit条件的handler类都需要执行handleRequest,只需要在handle(request)后,不立即return即可,稍微调整也可以满足需求。
其实,根据个人理解,职责链模式应该是需要依次执行每一个handler类的,完成每个handler判断是否hit来决定执行handle方法,如果是满足其中一个handler就立即退出的,更应该用策略设计模式,选择合适的策略handler类执行对应的handle方法。
import com.tj.designpatterns.chofresb.model.HandlerRequest; import com.tj.designpatterns.chofresb.model.UserRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Primary; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Primary @Order(1) @Component public class CustomerHandler extends AbstractHandler { private static final Logger log = LoggerFactory.getLogger(CustomerHandler.class); @Override protected boolean isHit(HandlerRequest request) { return request.getUserRole() == UserRole.CUSTOMER; } @Override protected void handle(HandlerRequest request) { log.info("handle customer execute, request: {}", request); } }
import com.tj.designpatterns.chofresb.model.HandlerRequest; import com.tj.designpatterns.chofresb.model.UserRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Order(2) @Component public class MerchantHandler extends AbstractHandler { private static final Logger log = LoggerFactory.getLogger(MerchantHandler.class); @Override protected boolean isHit(HandlerRequest request) { return request.getUserRole() == UserRole.MERCHANT; } @Override protected void handle(HandlerRequest request) { log.info("handle merchant execute, request: {}", request); } }
import com.tj.designpatterns.chofresb.model.HandlerRequest; import com.tj.designpatterns.chofresb.model.UserRole; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Order(3) @Component public class GuestHandler extends AbstractHandler { private static final Logger log = LoggerFactory.getLogger(GuestHandler.class); @Override protected boolean isHit(HandlerRequest request) { return request.getUserRole() == UserRole.GUEST; } @Override protected void handle(HandlerRequest request) { log.info("handle guest execute, request: {}", request); } }
如果是在springboot的实际项目中,可以通过再增加一个配置类初始化将AbstractHandler各个实现类链起来,利用@Order确定前后顺序。
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import java.util.List; @Configuration public class InitConfigHandler implements InitializingBean { @Autowired private List<AbstractHandler> abstractHandlerList; @Override public void afterPropertiesSet() throws Exception { abstractHandlerList.sort(AnnotationAwareOrderComparator.INSTANCE); int size = abstractHandlerList.size(); for (int i = 0; i < size - 1; i++) { abstractHandlerList.get(i).setNext(abstractHandlerList.get(i + 1)); } } }
这样当需要注入使用AbstractHandler类时,默认会注入@Primary的类作为职责链的第一链。实现了职责链模式与springboot很好的结合。