开闭原则是软件设计最重要的原则之一,设计具有良好可扩展性的业务架构极其依赖该原则。业务品种在增多,已有业务自身也在发展,需要设计一套统一,灵活,互相独立的业务架构。笔者在多个项目中,多次使用新型领导设计模式来设计可扩展的业务架构,觉得有必要总结出来,以供大家参考。本来是想把该模式归为23种设计模式之一,可能是由于能力有限,没能成功。
新型领导,把握大局(主流程),做事开明。新型领导设计模式算是笔者一种戏谑的叫法,只希望容易记忆。
曾经在N个项目中看到无数个if else,每一个业务种类一个else if,没有流程,没有扩展点,所有的东西塞到一个class里面。做得好一点的会抽取几个公用方法出来(这是代码复用,不是可扩展)。可能有的同学会反驳,“我从来不设计,不会写这样的代码”。不过我不信你没有看到过,或者被动写过类似的代码(历史包袱)。反正我被动写过,想哭的节奏…
Manager统领全局,控制流程,在具体的任务处理上,交给(委托)合适的人来做。
流程以及流程上一些通用的处理是封闭的,任务处理是开放的,A业务交由A处理器操作,B业务交由B处理器操作。示意图如下:
流程应该交由类似工作流引擎的系统处理,可扩展性的问题可用新型领导模式解决。
新型领导设计模式要解决两个问题。
一,Manager如何把多个Employee组织起来?Employee用个List存起来即可。如何发现Employee,最好通过Scan(扫描)或者注册的方式。二,如何把合适的任务交由合适的人处理?把决策权交给Employee,Manager询问谁能处理?谁先举手交给谁处理。
好了,新型领导模式的工作方式如下: Manager接到一个任务,逐个询问手下的员工,谁能处理这个任务,员工针对任务,评估并回馈Manager是或者否。把任务交给回馈YES的员工。
类图如下:
投资市场上的投资品有很多种,比如债券,股票,房产,基金,信托,保险等等,统称为资产,未来可能还需要支持更多的投资品。现在要设计一个资产系统,有一个功能是计算现值。所有资产都有这个功能,可是每一个的计算方式可能有些不一样。为简化起见,假设暂时仅支持债券和股票。
public interface Asset {
/**
* 资产名称
*/
String getAssetName();
/**
* 是否固定收益
*/
boolean isFixed();
}
public class BondAsset implements Asset {
@Override
public String getAssetName() {
return "债券";
}
@Override
public boolean isFixed() {
return true;
}
}
public class StockAsset implements Asset {
@Override
public String getAssetName() {
return "股票";
}
@Override
public boolean isFixed() {
return false;
}
}
public interface Handler {
/**
* 是否能够处理该种资产
*/
boolean canHandle(Asset asset);
/**
* 计算现值
*/
BigDecimal calculateValue(Asset asset);
}
public class BondHandler implements Handler {
@Override
public boolean canHandle(Asset asset) {
return asset instanceof BondAsset;
}
@Override
public BigDecimal calculateValue(Asset asset) {
// 查询股票数据库的上一收盘价
// 省略N多股票逻辑
return new BigDecimal(100);
}
}
public class StockHandler implements Handler {
@Override
public boolean canHandle(Asset asset) {
return asset instanceof StockAsset;
}
@Override
public BigDecimal calculateValue(Asset asset) {
// 查询债券数据库的上一收盘日中值
// 省略N多债券逻辑
return new BigDecimal(100);
}
}
public interface AssetService {
/**
* 计算现值
*/
BigDecimal calculateValue(Asset asset);
}
public class AssetServiceImpl implements AssetService {
@Autowired
private List<Handler> handlers;
@Override
public BigDecimal calculateValue(Asset asset) {
Handler handler = getHandler(asset);
if (handler == null) {
throw new RuntimeException("暂时不支持该类型的资产, 找不到对应的Handler");
}
return handler.calculateValue(asset);
}
/*
* 询问处理器,谁能处理该类型资产
*/
private Handler getHandler(Asset asset) {
if (handlers == null || handlers.isEmpty()) {
return null;
}
for (Handler handler : handlers) {
if (handler.canHandle(asset)) {
return handler;
}
}
return null;
}
}
AssetServiceImpl里面的handlers,是通过Spring的@Autowired运行时注入的。其它的方式包括XML配置注册,API调用注册,ClassPath扫描等。
Asset和Handler之间的mapping关系,每一次都调用getHandler,如果handlers数量太多,效率可能比较差。应该尝试HashMap等其它策略。
理想状态下,新增资产,只需要实现Asset,实现Handler即可。比如现在需要支持基金,那么写FundAsset和FundHandler两个类,连配置都不需要。完美的体现开闭原则。
新型领导设计模式有Facade和State设计模式的影子,统一的处理入口体现Facade,By上下文来选择不同的处理方式,体现State。有可扩展性设计需要的时候,不妨用它来验证一下,把成篇的If Else扔掉吧。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/kimylrong/article/details/47125037