学设计模式第一次听到这个模式时被迷惑了,以为所谓的组合模式是跟面向对象编程里的组合概念的一样
// 想象中的组合模式class Car { private Door door; private Wheel Whee;}
读了 GOF 的设计模式之后,书里是将组合模式描述为
将对象组合成树形结构的部分-整体层次结构,使得客户使用单个对象或组合对象都有一致性
也就是说组合部分与被组合部分在对外表现上,应该都是一致的,也就是其实是这样的
class Node { private Node part1; private Node part2;}
真正让我理解组合模式和它的妙用是在《领域驱动设计》这本书里面,作者提出了一个航线的概念,也就是这样,通过组合基本组件以达到功能更强大的一个组件
interface Route { Route segement1, segement2;} // 路线class NationalHighway implements Route{} // 国道class CountryRoad implements Route {} // 乡道
所谓策略,则可以理解为针对某种特定问题的算法,由于不同的算法各有优劣,所以需要将策略抽象为一个接口,让客户代码根据需求选择不同策略来解决问题,代码如下
interface Strategy{ void execute(..);}class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } void execute(){ strategy.execute(..); }}class StrategyA implements Strategy{ // 具体实现}// 使用Context context = new Context(new StrategyA());context.execute();
组合与策略两者的结合,不仅可以充分利用组合模式的灵活性,同时也可以利用策略模式的不同算法可选择性
interface Strategy{ void execute(..);}class StrategyA implements Strategy{ // 具体实现}class StrategyB implements Strategy{ // 具体实现}// 组合策略class CompositeStrategy implements Strategy { private Strategy strategyA, strategyB;}
通过组合不仅可以显式编程,交由不同的具体客户满足不同的需求,同时细粒度的策略也暴露了出去,也能让策略更有针对性及可选择性,更进一步,可以使用工厂模式将策略的组装与生成封装在工厂内部,这样客户代码也不必关心他使用的具体策略是什么,只要策略满足他的需求即可
这个业务场景是这样
我们有许多三方接口来获取某种信息
每种接口不仅需要单独对外提供服务,同时也需要聚合所有接口数据再对外提供服务
通过封装,这些返回的信息基本上都是一样的,但由于我们的项目在不同的地方运行,不同的地方可能有些接口可用,有些接口不可用,所以此时就通过组合策略模式来满足以上的所有需求
interface FetchInfoStrategy { Info fetch(...);}// 具体三方接口class ThirdPartAFetchInfoStrategy implements FetchInfoStrategy{...}class ThirdPartBFetchInfoStrategy implements FetchInfoStrategy{...}class ThirdPartCFetchInfoStrategy implements FetchInfoStrategy{...}// 组合三方接口class CompositeFetchInfoStrtegy implements FetchInfoStrategy { // 通过配置化动态注入 private static final List<Class<? extends FetchInfoStrategy>> STRATEGY_LIST; Info fetch(...) { // 循环调用策略,记录各个接口返回结果 // 合并结果并返回 }}
通过这样子的组合策略,不仅满足了需求,也为后续的优化留下了空间,若想通过异步调用各个接口,或者调整具体合并逻辑,都可以通过新增一个组合策略,避免修改老代码带来预期之外的问题