新型领导设计模式—设计可扩展性的业务架构

开闭原则是软件设计最重要的原则之一,设计具有良好可扩展性的业务架构极其依赖该原则。业务品种在增多,已有业务自身也在发展,需要设计一套统一,灵活,互相独立的业务架构。笔者在多个项目中,多次使用新型领导设计模式来设计可扩展的业务架构,觉得有必要总结出来,以供大家参考。本来是想把该模式归为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;
    }
}

例子补充说明

  1. AssetServiceImpl里面的handlers,是通过Spring的@Autowired运行时注入的。其它的方式包括XML配置注册,API调用注册,ClassPath扫描等。

  2. Asset和Handler之间的mapping关系,每一次都调用getHandler,如果handlers数量太多,效率可能比较差。应该尝试HashMap等其它策略。

  3. 理想状态下,新增资产,只需要实现Asset,实现Handler即可。比如现在需要支持基金,那么写FundAsset和FundHandler两个类,连配置都不需要。完美的体现开闭原则。

后记

新型领导设计模式有Facade和State设计模式的影子,统一的处理入口体现Facade,By上下文来选择不同的处理方式,体现State。有可扩展性设计需要的时候,不妨用它来验证一下,把成篇的If Else扔掉吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章