策略模式
在公司内部的供应链物流系统中,会与第三方物流承运商的系统进行对接。为了减少对对方系统的依赖,交互设计成“通知-反查”的形式,即当物流订单 “状态” 发生变更时,通过统一接口通知到我们系统,这边再根据不同的通知去做相应的处理。
比如:订单确认、拒绝、完成,车辆启运,位置更新等等的通知
在没有使用策略模式下,我们可能会写成这样:
1 2 3 4 5 6
| if (noticeType == 订单确认) { } else if (noticeType == 位置更新) { } ....等等其它逻辑分支
|
每次新增通知都要这边新增一个分支,到最后可能会非常长,后续的扩展和维护也会变得复杂且容易出错。策略模式是解决 if-else
代码块过长的方法之一,且后续维护与变更会变得很容易
策略定义
通知接口包含获取通知类型和处理通知两个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public interface INotice<V> {
V notice(CallbackParam param, String merchantNo);
List<NoticeTypeEnum> getNoticeType();
|
各个具体的处理类都需要实现上面两个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
@Slf4j @Componet @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class LocationNotice implements INotice<Boolean> { @Override public Boolean notice(CallbackParam param, String merchantNo) { }
@Override public List<NoticeTypeEnum> getNoticeType() { return Lists.newArrayList(NoticeTypeEnum.LOCATION_UPDATE); } }
@Slf4j @Componet @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class OrderCompletedNotice extends INotice<Boolean> {
@Override public Boolean notice(CallbackParam param, String merchantNo) { return Boolean.TRUE; }
@Override public List<NoticeTypeEnum> getNoticeType() { return Lists.newArrayList(NoticeTypeEnum.ORDER_CAR_COMPLETE); } }
|
策略的管理与获取
在接收到外部系统请求后,会根据不同的通知类型找到对应的处理类,然后由处理类来执行。这边结合 Spring
容器来管理,在构造 NoticeFactory
时让容器把所有通知处理类注入进来,然后循环转为map方便获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Compoent public class NoticeFactory {
public final Map<Integer, INotice<?>> NOTICE_MAP;
public NoticeFactory(List<INotice<?>> list) { NOTICE_MAP = Maps.newHashMap(); list.forEach(handle -> { List<NoticeTypeEnum> noticeType = handle.getNoticeType(); noticeType.forEach(e -> NOTICE_MAP.put(e.getCode(), handle)); }); } public INotice getNotice(Integer noticeType) { return NOTICE_MAP.get(noticeType); } }
|
策略使用
上面已经将所有策略类以key:通知类型,value:处理器对象放在了map中,这边就简单的根据类型来获取即可
1 2
| CallbackParam param = "外部请求信息"; Boolean result = NoticeFactory.getNotice(param.getNoticeType()).notice(param, merchantNo);
|
责任链模式
这个功能是从旧的用户系统同步用户到新的SSO系统中,方便已有的系统切换到SSO,以及后续用户信息有变更时能自动同步。同步通过mq的方式,当人员信息有变更时会从旧的用户系统发一条消息出来,消息包含基本信息、公司组织、岗位部门等
面对这样的业务,我们通常会采用面向过程的设计方法将流程拆分成N个步骤,每个步骤执行独立的逻辑:
1 2 3 4 5 6 7
| public void doSync() { }
|
如上代码是不符合开闭原则的,修改其中一个步骤仍然可能影响其他步骤(同一个类修改,不符合开闭原则)。当逻辑复杂后,后续的扩展和维护会容易出错,其他人接手也需要更多的时间。
在这种场景下,有一种通过责任链模式,可以将这些子步骤封装成独立的handler,然后通过pipeline将其串联起来
责任链的定义
常见的责任链模式会设计如下:
这边使用了自动生成责任链模式代码的工具 foldright/auto-pipeline
,在需要生成pipeline的接口上加上 @AutoPipeline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@AutoPipeline public interface Sync {
boolean sync(SyncUserDTO param); }
|
会自己生成handle接口,名称为pipeline接口名+Handler。即:SyncHandler
1 2 3
| public interface SyncHandler { boolean sync(SyncUserDTO param, SyncHandlerContext syncHandlerContext); }
|
然后自定义handler去实现SyncHandler即可,这里分成了处理基本信息、用户组织、岗位部门、用户默认角色等几个处理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
@Slf4j public class UserInfoHandler implements SyncHandler {
@Override public boolean sync(SyncUserDTO param, SyncHandlerContext syncHandlerContext) {
return syncHandlerContext.sync(param); }
}
@Slf4j public class UserOrgHandler implements SyncHandler {
@Override public boolean sync(SyncUserDTO param, SyncHandlerContext syncHandlerContext) { return syncHandlerContext.sync(param); } }
@Slf4j public class UserDeptPostHandler implements SyncHandler {
@Override public boolean sync(SyncUserDTO param, SyncHandlerContext syncHandlerContext) { return syncHandlerContext.sync(param); } }
@Slf4j public class DefaultRoleHandler implements SyncHandler {
@Override public boolean sync(SyncUserDTO param, SyncHandlerContext syncHandlerContext) { return syncHandlerContext.sync(param); } }
|
责任链使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| UserInfoHandler userInfoHandler = new UserInfoHandler(params);
UserOrgHandler userOrgHandler = new UserOrgHandler(params);
DefaultRoleHandler defaultRoleHandler = new DefaultRoleHandler(params);
UserDeptPostHandler userDeptPostHandler = new UserDeptPostHandler(params);
SyncPipeline syncPipeline = new SyncPipeline() .addLast(userInfoHandler) .addLast(userOrgHandler) .addLast(defaultRoleHandler) .addLast(userDeptPostHandler);
SyncUserDTO syncUser = ""; syncPipeline.sync(syncUser);
|