基于职责设计对象
最关键的软件开发工具是受过良好设计原则训练的思维,而不是UML或其他任何技术。
RDD是思考OO软件设计的一般性隐喻。把软件对象想象成具有某种职责的人,他要与其他人协作以完成工作。RDD使我们把OO设计看作是有职责对象进行协作的共同体。
分配职责的基本模式是GRASP。
创建者模式
问题:谁创建类A的实例?
建议:如果以下条件为真时(越多越好),将创建类A实例的职责分配给类B:
1、B“包含”或组成聚集了A。
2、B记录A。
3、B紧密的使用A。
4、B具有A的初始化数据。
首选聚集或包含A的类B。
注意:A和B指的都是软件对象而不是领域模型对象。
禁忌:对象的创建常常具有相当的复杂性。在一些情况下,更适合使用工厂。
信息专家模式
问题:给对象分配职责的基本原则是什么?
建议:把职责分配给具有完成该职责所需信息的那个类。把职责和数据置于一处,把服务与其属性置于一处。
禁忌:相比较而言系统关注更为重要,设计要分离主要的系统关注。例如:领域对象加入持久化逻辑成为充血模型,这就把应用逻辑与数据库逻辑混合起来了(不良设计)。
低耦合模式
问题:如何减少因变化产生的影响?(高耦合并不是问题所在,问题是与某些方面不稳定的元素之间的高耦合)
建议:分配职责以使(不必要的)耦合保持在较低的水平。(信息专家模式支持低耦合)
控制器模式
问题:在UI层之上首先接受和协调系统操作的对象是什么?
建议:把职责分配给能代表下列选择之一的对象:
1、代表全部“系统”、“根对象”、运行软件的设备或主要的子系统(外观控制器的变体)。
2、代表发送系统操作的用例场景(用例或会话控制器)。
高内聚模式
问题:怎样使对象保持有内聚、可理解和可管理,同时具有支持低耦合的附加作用?
建议:职责分配应保持高内聚。委派职责。内聚性低的类通常表示大粒度的抽象,或承担了本该委托给其他对象的职责。
多态模式
问题:如何处理基于类型的选择?如何创建可插拔的软件构件?
建议:当相关选择或行为随类型(类)有所不同时,使用多态为变化的行为类型分配职责。不要测试对象的类型,也不要使用条件逻辑来执行基于类型的不同选择。
经验:如果有一个具有抽象超类C1的类层次结构,可以考虑对应于C1中的公共方法特征标记来定义接口I1,然后声明C1来实现接口I1。
纯虚构模式
问题:当并不想违背高内聚和低耦合或其他目标,但基于专家模式的方案又不合适时,哪些对象应承担这一职责?
建议:人为制造类,由该类来承担一组高内聚的职责。该类并不代表问题领域的概念-是虚构的事物。例如DAO
纯虚构通常基于相关的功能性进行划分,因此这是一种以功能为中心的对象。
间接性模式
问题:为了避免两个或多个事物之间的直接耦合,应该如何分配职责?
建议:将职责分配给中介对象。例如,Adapter
间接性的动机通常是为了低耦合,并且大多数间接性中介都是纯虚构的。
防止变异模式
问题:如何设计对象、子系统和系统,使其内部的变化或不稳定性不会对其他元素产生不良影响?
建议:创建稳定的接口。
不要和陌生人讲话:约束了应该在方法里给哪些对象发送消息。它要求在方法里,只应给以下对象发送消息:
1、this对象(自身)
2、方法的参数
3、this的属性
4、作为this属性的集合中的元素
5、在方法中创建的对象
典型违反该原则的例子: F f=foo.getA().getB().getC().getD().getE().getF();
命令-查询分离原则:
执行动作(更新、调整,等等)的命令方法,这种方法通常具有改变对象状态等副作用,并且是void的(没有返回值)。
向调用者返回数据的查询,这种方法没有副作用,不会永久性地改变任何对象的状态。
关键在于:一个方法不应该同时属于以上两种类型。
在绘制交互图时考虑和决定职责分配。然后在类图的方法分栏里概括职责分配结果,方法是职责的具体实现。
最关键的软件开发工具是受过良好设计原则训练的思维,而不是UML或其他任何技术。
RDD是思考OO软件设计的一般性隐喻。把软件对象想象成具有某种职责的人,他要与其他人协作以完成工作。RDD使我们把OO设计看作是有职责对象进行协作的共同体。
分配职责的基本模式是GRASP。
创建者模式
问题:谁创建类A的实例?
建议:如果以下条件为真时(越多越好),将创建类A实例的职责分配给类B:
1、B“包含”或组成聚集了A。
2、B记录A。
3、B紧密的使用A。
4、B具有A的初始化数据。
首选聚集或包含A的类B。
注意:A和B指的都是软件对象而不是领域模型对象。
禁忌:对象的创建常常具有相当的复杂性。在一些情况下,更适合使用工厂。
信息专家模式
问题:给对象分配职责的基本原则是什么?
建议:把职责分配给具有完成该职责所需信息的那个类。把职责和数据置于一处,把服务与其属性置于一处。
禁忌:相比较而言系统关注更为重要,设计要分离主要的系统关注。例如:领域对象加入持久化逻辑成为充血模型,这就把应用逻辑与数据库逻辑混合起来了(不良设计)。
低耦合模式
问题:如何减少因变化产生的影响?(高耦合并不是问题所在,问题是与某些方面不稳定的元素之间的高耦合)
建议:分配职责以使(不必要的)耦合保持在较低的水平。(信息专家模式支持低耦合)
控制器模式
问题:在UI层之上首先接受和协调系统操作的对象是什么?
建议:把职责分配给能代表下列选择之一的对象:
1、代表全部“系统”、“根对象”、运行软件的设备或主要的子系统(外观控制器的变体)。
2、代表发送系统操作的用例场景(用例或会话控制器)。
高内聚模式
问题:怎样使对象保持有内聚、可理解和可管理,同时具有支持低耦合的附加作用?
建议:职责分配应保持高内聚。委派职责。内聚性低的类通常表示大粒度的抽象,或承担了本该委托给其他对象的职责。
多态模式
问题:如何处理基于类型的选择?如何创建可插拔的软件构件?
建议:当相关选择或行为随类型(类)有所不同时,使用多态为变化的行为类型分配职责。不要测试对象的类型,也不要使用条件逻辑来执行基于类型的不同选择。
经验:如果有一个具有抽象超类C1的类层次结构,可以考虑对应于C1中的公共方法特征标记来定义接口I1,然后声明C1来实现接口I1。
纯虚构模式
问题:当并不想违背高内聚和低耦合或其他目标,但基于专家模式的方案又不合适时,哪些对象应承担这一职责?
建议:人为制造类,由该类来承担一组高内聚的职责。该类并不代表问题领域的概念-是虚构的事物。例如DAO
纯虚构通常基于相关的功能性进行划分,因此这是一种以功能为中心的对象。
间接性模式
问题:为了避免两个或多个事物之间的直接耦合,应该如何分配职责?
建议:将职责分配给中介对象。例如,Adapter
间接性的动机通常是为了低耦合,并且大多数间接性中介都是纯虚构的。
防止变异模式
问题:如何设计对象、子系统和系统,使其内部的变化或不稳定性不会对其他元素产生不良影响?
建议:创建稳定的接口。
不要和陌生人讲话:约束了应该在方法里给哪些对象发送消息。它要求在方法里,只应给以下对象发送消息:
1、this对象(自身)
2、方法的参数
3、this的属性
4、作为this属性的集合中的元素
5、在方法中创建的对象
典型违反该原则的例子: F f=foo.getA().getB().getC().getD().getE().getF();
命令-查询分离原则:
执行动作(更新、调整,等等)的命令方法,这种方法通常具有改变对象状态等副作用,并且是void的(没有返回值)。
向调用者返回数据的查询,这种方法没有副作用,不会永久性地改变任何对象的状态。
关键在于:一个方法不应该同时属于以上两种类型。
在绘制交互图时考虑和决定职责分配。然后在类图的方法分栏里概括职责分配结果,方法是职责的具体实现。