将设计模式应用于模型设计
-
策略模式
策略模式着重解决以下类型的需求:
❑ 算法与多种变体需要不时替换。
❑ 未来有新增的算法。
❑ 一个类中某个行为有较多的分支,且需要时常维护。
❑ 希望隐藏算法的逻辑或数据。 -
策略模式的建模步骤如下:
1)找到使用多种算法处理任务的领域模型,就是那种有很多逻辑分支,且不断变化,让人头疼的地方。比如订单模型Order和数据处理模型DataProcessor。
2)运用“面对接口编程思想”,在领域模型内声明接口成员,用接口的处理替代所有的处理分支,接口方法的命名要符合通用语言。
3)将条件分支的处理逻辑或对象封装成不同的策略类,实现上面抽象出的接口。
4)绑定具体策略类到接口的逻辑,组合规则可以写在配置文件中由工厂完成,也可以由用户自行决定。 -
组合模式
组合模式的建模步骤如下:
1)找到组合策略的应用场合:由于需要功能排列组合而产生类爆炸的地方;在用户看来是一个简单个体,但其实背后是多个个体组合的情况。
2)根据需求提炼出这些组件的共同接口。如复杂的优惠策略中的结算费用、多级仓库中的统计库存和智能制造中的计算成本。
3)设计组合部件,它本身要实现共同接口,另外还要声明接口的集合用来扩展。
4)设计叶子节点,它要实现共同接口,但无须再声明接口集合成员变量。
5)按需组合部件与叶子节点(可由工厂执行)。
6)用户通过接口使用组合好的模型。 -
门面模式
-
门面模式通常出现在领域层之外的应用服务层,它的建模步骤如下:
1)从通用语言中找到值得封装的具有业务含义的操作,其特征为:
❑ 业务虽然简单,但涉及多个模型的复杂交互。
❑ 后面隐藏着其他子系统,需要数据转换等复杂操作。
2)用单独的类和富含业务含义的接口封装这些模型和子系统。
3)门面可能位于领域层外的应用层中,让用户使用门面模式包装的业务接口,而不是直接使用领域模型。 -
模板模式
-
建模步骤如下:
1)在领域中发掘隐含的工作流逻辑,即略有不同但是概念上相似的步骤。当然,如果工作流是显式的,那么可以直接拿来使用。
2)创建流程抽象基类。将工作流的流转逻辑体现在基类的对应方法中(如VehicleProduct-Line中的StartWork()方法)。
3)将后续会发生变化的处理逻辑声明为抽象方法。
4)创建继承自基类的具体工作流对象,并实现自己具体的处理逻辑。
5)配合工厂返回具体的工作流对象供用户使用。 -
单例模式
-
工具类:提供系统公用方法的工具类也会私有化构造函数,并且所有方法都为静态方法。它与单例模式的区别如下:
❑ 工具类不保存状态,仅提供无状态函数,而单例模式可以有状态,比如存一些统计数据等全局变量。
❑ 工具类不具有多态性,而单例模式可以被继承。
❑ 单例模式是一个模型,而工具类只是方法的集合。 -
单例模式的建模步骤如下:
1)找到领域中具备以下共性的需求:
❑ 有限资源的统一协调。
❑ 计算存储全局性变量。
❑ 解决相同对象过多的性能问题。
2)将处理上述任务的模型单例化,需要完成以下几步:
❑ 私有构造函数防止在外部实例化。
❑ 保存唯一实例的静态的私有变量。
❑ 初始化并获得唯一实例的静态方法。
3)单例化改造后,添加解决冲突的算法、资源分配方法,以及全局变量等业务方法和数据。
4)在之前实例化模型的代码中,如果使用了构造函数或工厂,都替换为单例模式的静态方法来获得实例。 -
观察者模式
-
建模步骤如下:
1)找到关心的领域事件。
2)通过事件找到对应的触发操作,进而定位所在模型。
3)所在模型即为观察目标,观察目标实现Object接口的3个操作(通知观察者、添加和删除观察者),同时定义一个Observer接口的集合成员。
4)找到事件的消费者,它可能是为了解耦从观察目标拆解出来的新对象,也可能是领域中的其他模型,即观察者。
5)观察者实现Observer接口,实现具体的事件响应逻辑。
注意,模型的定义要符合通用语言,确保领域专家理解你的模型设计。 -
适配器模式
-
建模步骤如下:
1)评估已有对象的能力能否胜任,包括评估已有对象的可见性和访问权限等因素。比如,加法运算的对象适配后可以做乘法,但其他运算可能根本就无法适配。
2)确定任务接口。
3)确定转换的算法,包括参数的处理等。
4)实现适配器类。
5)利用客户端或者通过工厂方法输出适配器类,将耦合了被包装对象的地方都替换为适配器类。 -
代理者模式
-
建模步骤
代理者模式的建模步骤如下:
1)找到符合以下需求特征的对象,为其创建代理:
❑ 所有远程对象。为远程对象都创建本地代理是一个屡试不爽的优秀实践。
❑ 访问需要控制的对象。不论是权限还是前面提到的配额等领域逻辑的控制。
❑ 访问比较复杂的对象。如需要通过复杂计算生成的对象。
2)创建代理类,并按照代理对象的类别将以下内容封装到代理对象内:
❑ 为远程对象提供本地替身对象,在远程对象无法及时给予反馈时,使用本地对象。要综合平衡用户体验和实时性的要求。
❑ 访问需要控制的对象,将控制逻辑封装在代理类中。
❑ 访问比较复杂的对象,将复杂访问逻辑封装在代理类中。
3)要保证代理类的接口与原始对象一致,调用者感觉不到两者的差别。
4)将代码中所有对真实对象的访问都替换为对代理的访问。 -
访问者模式
-
建模步骤
访问者模式的建模步骤如下:
1)找到需要扩展行为的模型,让其实现被访问者接口(Accept方法)。
2)按关注点对扩展行为进行分类,构成不同的访问者,它们都实现访问者接口(Visit方法)。
3)在访问者类中,通过对原模型的访问实现新的业务需求。
4)在工厂中或客户端,按需让模型接收不同的访问者即可。访问者自动完成自身的扩展逻辑,不需要额外操作。 -
状态模式
-
建模步骤
状态模式的建模步骤如下:
1)找到具有多种状态的领域模型,它可能来自通用语言,也可能是那些有很多逻辑分支的地方。
2)将不同状态下的不同处理逻辑提取到状态接口或抽象类中。
3)将模型中不同的处理逻辑部分转换为由状态接口或抽象类处理。
4)按逻辑分支数量创建具体状态类,并实现状态接口或抽象类。
5)确定状态转换条件。
6)将转换条件实现在含有状态的模型中(第一个代码例子)或者具体状态类中(第二个代码例子),又或者外部的配置文件中。
可以看到,前4步与策略模式相似,最后2步是状态模式独有的,也是其能实现“自动”的原理所在。
- 职责链模式
- 建模步骤
职责链模式的建模步骤如下:
1)确定请求中需要不同处理的逻辑。
2)为该请求设计接口。不同处理的逻辑体现为实现该接口的具体处理类。注意,每一个处理类处理的数据可能有交叉,但逻辑上不应重复或矛盾。
3)工厂根据需求组装不同的职责链。这个任务最好不要交给客户来做。
4)用户直接使用工厂返回的职责链的简单对象即可,无须关心职责链有多长、需要多少额外的处理。这些都是由工厂按需灵活定制的。 - 桥接模式
- 建模步骤
桥接模式的建模步骤如下:
1)识别变化的维度和桥接它们的场景。
2)一个维度设计一个接口,它代表此维度对象要完成的任务。
3)将该维度所有变量继承实现该接口。
4)设计“桥”模型,它是多个维度一起工作的场景。比如“用户画像”。
5)工厂组装好桥模型提供给用户使用,如“用户画像工厂”。