1 Map+函数式接口方法
1.1 场景
在工作中, 经常会遇到大量条件判断的情况, 因此一般使用策略模式来定义各种业务行为
但缺点也明显:
1.2 Map+函数式接口方法使用
用上了Java8的新特性lambda表达式
- 判断条件放在key中
- 对应的业务逻辑放在value中
这样子写的好处是非常直观,能直接看到判断条件对应的业务逻辑
需求:根据资源类型resourceType和不同的入参规则, 来返回不同的业务编码
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
| @Service public class QueryGrantTypeService { @Autowired private GrantTypeService grantTypeService; private Map<String, Function<BusinessObject,String>> grantTypeMap=new HashMap<>();
@PostConstruct public void dispatcherInit(){ grantTypeMap.put(RiskNotificationEnum.VULNERABILITY_NOTICE.getCode(),businessObject-> grantTypeService.getVulCode(businessObject)); grantTypeMap.put(RiskNotificationEnum.SECURITY_EVENT_TROUBLESHOOTING.getCode(),businessObject-> grantTypeService.getSecCode(businessObject)); grantTypeMap.put(Constants.ISSUE_COMMAND, businessObject-> grantTypeService.getZlCode(businessObject)); } public String getResult(String resourceType, BusinessObject businessObject){ Function<BusinessObject,String> result=grantTypeMap.get(resourceType); if(result!=null){ return result.apply(businessObject); } return null; } }
|
BusinessObject 是个公用接口, 不同的业务类都可以继承BusinessObject, 不会对原本数据有任何影响, 在最终实现的方法中可以转换为原本的对象
1 2 3 4 5 6
|
public interface BusinessObject { }
|
具体方法实现
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
| public String getSecCode(BusinessObject businessObject) { SecurityEventDO securityEventDO = (SecurityEventDO) businessObject; log.info("GrantTypeService-getSecCode:{}", JSON.toJSONString(securityEventDO)); String timestamp = getTimeStr(); String pre = getKey(NoticeSourceEnum.class, securityEventDO.getEventSource(), SystemManagerConstant.SEC); String key = RiskNotificationEnum.SECURITY_EVENT_TROUBLESHOOTING.getCode(); String countStr = getValue(key); String attackSource = getCode(securityEventDO.getAttackSource(), AttackSourceEnum.class); String assetType = getCode(securityEventDO.getAssetType(), AssetTypeEnum.class); String attackType = getCode(securityEventDO.getAttackType(), AttackTypeEnum.class); if (securityEventDO.getAttackType().startsWith("其他")) { attackType = "8"; } String alertSource = getCode(securityEventDO.getAlertSource(), AlertSourceEnum.class); String secCode = pre + timestamp + attackSource + assetType + attackType + alertSource + "-" + countStr; log.info("安全事件编码为:{}", secCode); return secCode; }
|
直接使用controller层接口调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| @RestController public class GrantTypeController { @Autowired private QueryGrantTypeService queryGrantTypeService; @PostMapping("/grantType") public String test(String resourceName){ return queryGrantTypeService.getResult(resourceName); } }
|
1.3 总结
策略模式通过接口、实现类、逻辑分派来完成,把 if语句块的逻辑抽出来写成一个类,更好维护。
Map+函数式接口通过Map.get(key)来代替 if-else的业务分派,能够避免策略模式带来的类增多、难以俯视整个业务逻辑的问题。
2 责任链模式优化参数多重校验
2.1 场景
- 之前在做需求,写一个方法,先在前面做验证,
- if不满足A条件则return,
- if不满足B条件则return…
- 一共写了5个验证,等验证通过以后才执行下面的逻辑,
- 过了一阵产品提了需求,跟这个方法类似,
- 我又把这个方法copy了一份,只不过验证条件稍微有点不一样,变成6个验证了。
2.2 责任链模式
1)职责链模式(Chain of Responsibility Pattern),又叫==责任链模式==:为请求创建了一个接收者对象的链。
2)职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推
3)这种类型的设计模式属于==行为型模式==
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { Handler.Builder builder = new Handler.Builder(); builder.addHandler(new ValidateHandler()) .addHandler(new LoginHandler()) .addHandler(new AuthHandler()) .addHandler(new BusinessLogicHandler()); User user = new User(); user.setUserName("woniu"); user.setPassWord("666"); builder.build().doHandler(user); }
|
Handler抽象接口:
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
| public abstract class Handler<T> { protected Handler next; private void next(Handler next) { this.next = next; } public abstract void doHandler(User user); public static class Builder<T> { private Handler<T> head; private Handler<T> tail; public Builder<T> addHandler(Handler handler) { if (this.head == null) { this.head = this.tail = handler; return this; } this.tail.next(handler); this.tail = handler; return this; } public Handler<T> build() { return this.head; } } }
|
抽象实现
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
| public class AuthHandler extends Handler { @Override public void doHandler(User user) { if (!"管理员".equals(user.getRoleName())) { System.out.println("您不是管理员,没有操作权限"); return; } if (null != next) { next.doHandler(user); } } }
public class BusinessLogicHandler extends Handler { @Override public void doHandler(User user) { System.out.println("你好棒!"); } }
public class LoginHandler extends Handler { @Override public void doHandler(User user) { if (!"woniu".equals(user.getUserName()) || !"666".equals(user.getPassWord())) { System.out.println("用户名密码不正确"); return; } if (null != next) { next.doHandler(user); } } }
|
实体类
1 2 3 4 5 6 7 8 9
| @Data public class User { private String userName; private String passWord; private String roleName; }
|
3 业务编排功能
3.1 场景
- 写代码过程中经常使用到业务编排功能, 有时添加一些校验以及其他业务流程, 并不会影响其他业务流程的执行, 大量的业务代码会在一个方法中耦合, 每次修改都要重头去理解, 非常的麻烦, 这时候就需要用到业务编排
- 业务编排可以直接使用 LiteFlow 来完成, 但是项目中只有少部分逻辑需要业务编排, 则没有必要引用
- 因此可以使用
责任链模式 + 工厂模式 + 枚举
来完成业务编排
3.2 责任链模式 + 工厂模式 + 枚举
3.2.1 在工厂方法中使用责任链封装业务对象
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
| public class GatewayHandlerEnumFactory { private static GatewayDao gatewayDao = new GatewayImpl(); public static GatewayHandler getFirstGatewayHandler() { GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity(); GatewayHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity); if (firstGatewayHandler == null) { return null; } GatewayEntity tempGatewayEntity = firstGatewayEntity; Integer nextHandlerId = null; GatewayHandler tempGatewayHandler = firstGatewayHandler; while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) { GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId); GatewayHandler gatewayHandler = newGatewayHandler(gatewayEntity); tempGatewayHandler.setNext(gatewayHandler); tempGatewayHandler = gatewayHandler; tempGatewayEntity = gatewayEntity; } return firstGatewayHandler; }
private static GatewayHandler newGatewayHandler(GatewayEntity firstGatewayEntity) { String className = firstGatewayEntity.getConference(); try { Class<?> clazz = Class.forName(className); return (GatewayHandler) clazz.newInstance(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { e.printStackTrace(); } return null; } }
|
3.2.2 获取枚举配置项接口
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
|
public interface GatewayDao {
GatewayEntity getGatewayEntity(Integer handlerId);
GatewayEntity getFirstGatewayEntity(); }
public class GatewayImpl implements GatewayDao {
private static Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>(); static { GatewayEnum[] values = GatewayEnum.values(); for (GatewayEnum value : values) { GatewayEntity gatewayEntity = value.getGatewayEntity(); gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity); } } @Override public GatewayEntity getGatewayEntity(Integer handlerId) { return gatewayEntityMap.get(handlerId); } @Override public GatewayEntity getFirstGatewayEntity() { for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) { GatewayEntity value = entry.getValue(); if (value.getPreHandlerId() == null) { return value; } } return null; } }
|
3.2.3 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Data @AllArgsConstructor public class GatewayEntity { private Integer handlerId; private String name; private String conference; private Integer preHandlerId; private Integer nextHandlerId; }
|
3.2.4 枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public enum GatewayEnum { API_HANDLER(new GatewayEntity(1, "api接口限流", "com.woniu.zerenlianfactorydemo.afteryouhua.ApiLimitGatewayHandler", null, 2)), BLACKLIST_HANDLER(new GatewayEntity(2, "黑名单拦截", "com.woniu.zerenlianfactorydemo.afteryouhua.BlacklistGatewayHandler", 1, 3)), SESSION_HANDLER(new GatewayEntity(3, "用户会话拦截", "com.woniu.zerenlianfactorydemo.afteryouhua.SessionGatewayHandler", 2, 4)), ; GatewayEntity gatewayEntity; public GatewayEntity getGatewayEntity() { return gatewayEntity; } GatewayEnum(GatewayEntity gatewayEntity) { this.gatewayEntity = gatewayEntity; } }
|
3.2.5 责任链业务抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public abstract class GatewayHandler {
protected GatewayHandler next; public void setNext(GatewayHandler next) { this.next = next; } public abstract void service(); }
|
3.2.6 实现抽象类
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
| public class BlacklistGatewayHandler extends GatewayHandler { @Override public void service() { System.out.println("黑名单拦截"); if (this.next != null) { this.next.service(); } } }
public class ApiLimitGatewayHandler extends GatewayHandler { @Override public void service() { System.out.println("api接口限流"); if (this.next != null) { this.next.service(); } } }
public class SessionGatewayHandler extends GatewayHandler { @Override public void service() { System.out.println("用户会话拦截"); if (this.next != null) { this.next.service(); } } }
|
3.2.7 调用执行
1 2 3 4 5 6 7 8 9
|
public class GetewayClient { public static void main(String[] args) { GatewayHandler firstGatewayHandler = GatewayHandlerEnumFactory.getFirstGatewayHandler(); firstGatewayHandler.service(); } }
|
4 工厂模式+模板方法
4.1 场景
- 不同的业务场景走的是同一套流程,但是具体实现不同, 这样的话就可以将相同的部分抽为抽象方法,分别实现不同的业务逻辑
- 同时不同的对象可使用工厂模式进行维护。
4.2 工厂模式+模板方法
比如,我现在有一个业务是需要查询数据, 处理之后 组合为不同的Echars图形
4.2.1 工厂方法
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
| @Component public class ChartServiceFactory { private final Map<ChartType, AbstractChartService<EcharsOptionsRequest, ?, String>> serviceMap; @Autowired public ChartServiceFactory(List<AbstractChartService<EcharsOptionsRequest, ?, String>> services) { serviceMap = services.stream() .collect(Collectors.toMap(service -> { if (service instanceof LineChartService) return ChartType.LINE; if (service instanceof BarChartService) return ChartType.BAR; if (service instanceof PieChartService) return ChartType.PIE; throw new IllegalArgumentException("Unknown service type: " + service.getClass()); }, service -> service)); } public AbstractChartService<EcharsOptionsRequest, ?, String> getChartService(ChartType chartType) { return serviceMap.get(chartType); }
}
|
4.2.2 业务抽象模板
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
| @Slf4j @Service public abstract class AbstractChartService<T extends EcharsOptionsRequest, D, R> {
public R execute(T request) { List<D> data = queryData(request); if (validateData(data)) { log.info(getType().getDesc() + " 当前时间节点没有数据: {}", request); return emptyChart(request); } return processData(request, data); }
protected abstract List<D> queryData(T request);
protected abstract boolean validateData(List<D> data);
protected abstract R processData(T request, List<D> data); protected abstract R emptyChart(T request); protected abstract ChartType getType(); }
|
4.2.3 接口调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Autowired private ChartServiceFactory chartServiceFactory;
@Override public String getECharsOptions(EcharsOptionsRequest request) { ChartType chartType = ChartType.getByCode(request.getType()); if (chartType == null) { return "不支持的图表类型"; } AbstractChartService<EcharsOptionsRequest, ?, String> chartService = chartServiceFactory.getChartService(chartType); return chartService.execute(request); }
|