GRASP是从整体设计上解决耦合的问题,而GoF却是从具体实现上解决的,在这里我们不妨探讨一下。
设计模式GRASP其名称翻译过来就是“通用职责分配设计模式”,从字面上我们不难发现,“职责分配”是GRASP的核心。GRASP认为,在对象设计时,只要各个对象的职责分配清楚了,能够各司其职,耦合就会降低。因此,GRASP应用的一个非常重要的场景是,我们项目的业务需求已经分析清楚了,正准备开始设计对象。GRASP告 诉我们,一个系统里面到底应当有哪些对象,应当来源于领域模型,换句话说就是来源于现实时间中的事物。现实世界中有什么事物,我们软件空间中就应当有什么 对象。当然,现实世界中的事物不一定都需要在软件空间中有对应的对象,要根据需求而定,但软件空间中的对象应当对应于现实世界中的事物,这种设计原则有个 专用术语叫“低表示差异”。按照这个原则设计好了我们的对象以后,应当如何分配它们的职责呢?当然是来源于现实世界。我们的对象在现实世界中应当有什么职 责,那么我们的对象就应当有什么样的职责。如此分析,每个对象的职责就非常清楚,那么业务需求中的各种功能应当如何分配给对象呢?现实世界是怎样分配的, 软件世界就怎样分配的。最后,如何在各个功能中将对象组织起来呢?GRASP的专家模式解答了这个问题;对象应当由谁来创建,GRASP的创建者模式解答了这个问题。GRASP通过这样一个步骤,设计对象、分配职责、确定功能、建立联系,一个项目的整体框架就展现出来了,而这样一个框架必然是低耦合高内聚的,为什么呢?这方面的详细论述朋友们可以看我写的《(原创)一个优秀软件开发人员的必修课:GRASP软件开发模式浅析》,这里我就不再累赘了。但是,GRASP只解决了整体设计中的耦合问题,只解决了一部分,而另一部分需要依靠GoF。
前面我们说到运用GRASP进 行整体设计依靠的是现实世界和业务需求。这样的分析还没有介入任何技术的成分。但是随着我们的进一步分析,我们开始尝试运用各种具体的技术去实现这些业务 需求需要实现的功能,我们发现问题出现了。比如,我们在整体设计的时候设计的一组继承关系的对象,其它需要使用它们的对象如何去调用它们?去具体地调用它 们的某个子类吗?这显然不是一个好的方案,GoF的工厂模式告诉我们,这里需要设计一个工厂类。这里增加的这个工厂类不是来源于现实世界,GRASP称这样的对象为“纯虚对象”。纯虚对象是从现实对象中抽象出来的一些功能,但GRASP不能告诉我们应当抽象出哪些纯虚对象,解决这样的问题需要运用GoF。再比如,商场中的许多商品都需要打折,但是各种商品的打折策略其实并不是完全不同的,是有相似之处的,有的是按比例打折,有的是满500送100,有的是学生才打折。如此这般,如果我们对一个商品父类的所有商品子类都重载一遍自己“折扣”方法,显然不是一个好的设计,不如将所有的折扣方法抽象出来,形成抽象的“折扣策略”父类和具体的折扣子类,然后由各个商品子类自己去选择自己需要的折扣策略。如此这般,就运用了GoF的策略模式。通过以上分析,我们不难看出,GoF是在具体实现中去解决对象的耦合问题的。它是在GRASP分析的整体框架下,对一些具体的对象及其方法进行重新组织,解决对象耦合问题的。
现在,我们再换一个角度,从整个软件开发过程来分析GRASP和GoF。按照RUP的 设计流程,首先当然是设计用例模型和领域模型,然后就进入分析模型和设计模型阶段。但是非常神奇的是,分析模型和设计模型既非常相似,又没有一个明显的界 限来区分哪些是分析模型,哪些是设计模型。按照我的理解,分析模型是从不包含任何技术的,纯业务的角度开始对象分析的。不论是Java的项目、C++的项目还是Delphi的项目,不论是B/S的结构还是C/S的结构,分析模型的开始都是一样的。从分析模型的一开始,就是运用GRASP一 步一步的进行对象分析和设计的。通过这样的设计,对应于现实世界的一个一个对象被设计出来,然后赋予它们职责和功能,分配它们属性和方法,建立起它们相互 之间的联系与协作。分析完这些以后,它们的各个具体的属性和方法就需要开始实现,这时技术的东西开始介入,我们开始考虑把一些具体的实现抽象为接口和抽象 类,以适应今后的需求变化。这时候,GoF的一些设计模式开始广泛运用,纯虚对象开始一个一个出现。把具体的实现抽象为接口和抽象类,以适应今后的需求变化,是GoF一个非常重要的设计原则,GoF中的许多设计模式都是由此而生的。分析模型和设计模型的界线也许就是分析模型还仅仅只是分析阶段,而设计模型已经进入到了软件开发阶段,但这样的界线是模糊的,并没有一个绝对的时间点。
最后,一个很有意思的问题是,GRASP的作用大还是GoF的作用大?做分析的朋友可能说GRASP的作用大,因为所有问题越是在项目开发的早期解决,越是给项目带来的代价越小;做设计的朋友可能会说GoF的作用大,因为GRASP只是在对象分析的初期运用,而GoF的运用贯穿整个软件设计的始末,作用时间更长。我认为这个问题不好回答,它们各司其职,我们只有配合使用它们才能有效地提高我们的设计水平。
原创链接 http://fangang.iteye.com/blog/79728。