面向对象分析与设计设计原则与模式:设计优劣的标准和设计工具内容提要GRASP设计原则高级设计原则设计模式AOP编程什么是设计类?设计类是已经完成了规格说明并且达到能够被实现程度的类。设计类的来源通过分析类的精化得到的问题域,这里的精化包括添加实现细节解域-它是实用类库和诸如TIME、DATE、STRING等可复用组件的领域好的设计与差的设计一个面向对象的系统是由多个对象组成的系统,这些对象能够向其它对象发送消息来完成操作差的设计选择会导致系统和系统的构件比较脆弱和难以维护、理解、重用和扩展。要熟练地实现一个系统,在设计这个系统时运用面向对象的主要设计原则是实现该系统的基础设计应完成的工作在设计中,必须准确地说明类是如何履行它们的职责。必须完成以下事情:完整的属性集合,包括详细说明的名称、类型、可视性和一些默认值(可选的)将分析类指定的操作转化成一个或多个方法的完整集合。设计方式举例设计一个人事管理系统,其中的一个功能是对各种不同类型的员工,计算其当月的工资——不同类型的员工,拥有不同的薪金计算制度.结构化设计获得人事系统中所有可能的员工类型根据不同的员工类型所对应的不同的薪金制度,计算其工资enumEmployeeType{Engineer;Sales;Manager;…}//计算工资程序if(type==EmployeeType.Engineer){……}elseif(type==Employeetype.Sales){……}面向对象设计根据不同的员工类型设计不同的类,并使这些类继承自一个Employee抽象类,其中有一个抽象方法GetSalary。在各个不同的员工类中,根据自己的薪金制度,重写(override)GetSalary方法。面向对象设计(续)abstractclassEmployee{…publicabstractintGetSalary();}classEngineer:Employee{…publicoverrideintGetSalary(){…}}classSales:Employee{…publicoverrideintGetSalary(){…}}//显示工资程序Employeee=emFactory.GetEmployee(id);MessageBox.Show(e.GetSalary());示例场景需求改变了……随着客户公司业务规模的拓展,又出现了更多类型的员工,比如钟点工、计件工……等等,这对人事管理系统提出了挑战——原有的程序必须改变结构化做法:修改源代码,完整的测试流程。面向对象的做法:增加新代码,新增代码的测试。结论怎样才能设计“好的面向对象”?–遵循一定的面向对象设计原则–熟悉一些典型的面向对象设计模式GRASP模式GRASP(GeneralResponsibilityAssignmentSoftwarePatterns),中文名称为“通用职责分配软件模式”,GRASP一共包括9种模式,它们描述了对象设计和职责分配的基本原则。也就是说,如何把现实世界的业务功能抽象成对象,如何决定一个系统有多少对象,每个对象都包括什么职责,GRASP模式给出了最基本的指导原则。初学者应该尽快掌握、理解这些原则,因为这是如何设计一个面向对象系统的基础。可以说,GRASP是学习使用设计模式的基础。GRASP模式GRASP(GeneralResponsibilityAssignmentSoftwarePattern)通用职责分配软件模式描述了将职责分配给对象的基本原则九种基本GRASP模式信息专家(EXPERT)创建者(CREATOR)高内聚(HIGHCOHESION)低耦合(LOWCOUPLING)控制者(CONTROLLER)多态(Polymorphism)纯虚构(PureFabrication)中介者(Indirection)不要和陌生人讲话(Don’ttalktoStranger)Grasp模式基本概念GRASP模式比23种设计模式更重要更经典的GRASP模式责任是类间的一种合约或义务,也可以理解成一个业务功能,包括行为、数据、对象的创建等知道责任—表示知道什么行为责任—表示做什么Grasp模式基本概念(续)GRASP模式责任=知道责任+行为责任了解私有封装数据了解关联的对象了解能够派生或计算的事物完成对象初始化执行一些控制行为知道责任行为责任Grasp模式基本概念(续)责任不是类的方法,类的方法用于实现行为责任。责任更可以理解成是系统应提供的一个业务功能责任的分配可使用顺序图或协作图来表达面向对象设计过程就是将责任分配给对象的过程GRASP模式-信息专家信息专家模式是面向对象设计的最基本原则,是我们平时使用最多,应该跟我们的思想融为一体的原则。也就是说,我们设计对象(类)的时候,如果某个类拥有完成某个职责所需要的所有信息,那么这个职责就应该分配给这个类来实现。这时,这个类就是相对于这个职责的信息专家。例如:常见的网上商店里的购物车(ShopCar),需要让每种商品(SKU)只在购物车内出现一次,购买相同商品,只需要更新商品的数量即可。(SPID)来唯一区分商品,而商品编号是唯一存在于商品类里的,所以根据信息专家模式,应该把比较商品是否相同的方法放在商品类里。总结为“谁知道谁负责”GRASP模式-专家(举例)例子,如果有一个类是专门处理字符串相关的类,那么这个类只能有字符串处理相关的方法,而不要将日期处理的方法加进来。也就是提高软件高内聚一种原则。GRASP模式-专家(续)信息专家模式核心思想:把职责分配给具有完成某项职责所需信息的个体.信息专家模式在职责分配中使用得非常广泛,它是对象设计中经常使用的基本指导原则.职责的履行需要信息,而信息往往分布在不同的对象中.这就意味着许多“部分”的信息专家有时需要协作才能来完成一个任务GRASP模式-专家(优点)因为对象使用自己的信息来实现服务,所以信息的封装性得以维持.低耦合/健壮性/易维护性.行为分散在不同的类中,这些类各自具有完成行为所需要的信息.这些“轻量级”的类易于理解和维护.GRASP模式-创建者实际应用中,符合下列任一条件的时候,都应该由类A来创建类B,这时A是B的创建者:a.A是B的聚合b.A是B的容器c.A持有初始化B的信息(数据)d.A记录B的实例e.A频繁使用B如果一个类创建了另一个类,那么这两个类之间就有了耦合,也可以说产生了依赖关系。依赖或耦合本身是没有错误的,但是它们带来的问题就是在以后的维护中会产生连锁反应,而必要的耦合是逃不掉的,我们能做的就是正确地创建耦合关系,不要随便建立类之间的依赖关系,那么该如何去做呢?就是要遵守创建者模式规定的基本原则,凡是不符合以上条件的情况,都不能随便用A创建B。简单一句话:我要使用你,所以请让我创建你。一个GUI的例子有一个用户窗口MainWindow,包含Menu,ToolBar,Dialog等,Dialog上布置有Textbox,Button等元素。我们应用Creator(创建者)模式,先为它们设计好具有阶层关系的类图MyMenu,MyToolBar,MyDialog由MainWindow所包含,MyTextbox,MyButton被MyDialog包含,MainWindow由Main类调用它们的实例的创建职责的分配应该是:MainWindow的实例由Main创建MyMenu,MyToolbar,MyDialog的实例由MainWindow创建,MyTextbox,MyButton的实例由MyDialog创建。创建者模式例子GRASP模式-创建者(续)创建者模式指导怎样分配“与创建对象”相关的职责。创建者模式的基本目的是找到一个在任何情况下都与被创建对象相关联的创建者,选择这样的类作为创建者能支持低耦合。集合聚集了部分,容器包含了内容,记录器记录了被记录的数据,这些类之间的关系在类图中非常普遍.CreatorPattern建议:封装的容器类和记录器类是创建“自己包含或者记录的元素”的很好候选者.GRASP模式-创建者(优点)支持低耦合,这种设计意味着具有更低的维护依赖性和更高的重用机会.创建者模式之所以可能不增加耦合性是由于被创建类对于创建类而言已经可见了,正是因为已存在的关联使得它成为创建者.A是B的创建者,则A更容易和B成为一个整体。GRASP模式-低耦合模式低耦合模式的意思就是要我们尽可能地减少类之间的连接。其作用非常重要:a.低耦合降低了因一个类的变化而影响其他类的范围。b.低耦合使类更容易理解,因为类会变得简单,更内聚。下面这些情况会造成类A、B之间的耦合:a.A是B的属性b.A调用B的实例的方法c.A的方法中引用了B,例如B是A方法的返回值或参数。d.A是B的子类GRASP模式-低耦合模式(续)耦合:是一个类与其它类关联、知道其它类的信息或者依赖其它类的强弱程度的度量一个具有高耦合度的类有如下问题:其它类的改变会迫使这个类改变其自身的局部定义难以孤立的理解它难以重用GRASP模式-低耦合模式(续)1无直接耦合:2数据耦合:指两个模块之间有调用关系,传递的是简单的数据值,相当于高级语言的值传递;3标记耦合:指两个模块之间传递的是数据结构,如高级语言中的数组名、记录名、文件名等这些名字即标记,其实传递的是这个数据结构的地址;4控制耦合:指一个模块调用另一个模块时,传递的是控制变量(如开关、标志等),被调模块通过该控制变量的值有选择地执行块内某一功能;5公共耦合:指通过一个公共数据环境相互作用的那些模块间的耦合。公共耦合的复杂程序随耦合模块的个数增加而增加。6内容耦合:这是最高程度的耦合,也是最差的耦合。当一个模块直接使用另一个模块的内部数据,或通过非正常入口而转入另一个模块内部。GRASP模式-高内聚模式内聚性又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。高内聚也可以说是一种隔离,就像人体由很多独立的细胞组成,大厦由很多砖头、钢筋、混凝土组成,每一个部分(类)都有自己独立的职责和特性,每一个部分内部发生了问题,也不会影响其他部分,因为高内聚的对象之间是隔离开的。GRASP模式-高内聚模式(续)内聚:是一个类中的各个职责之间相关程度和集中程度的度量一个低内聚的类存在如下问题:难以理解难以重用难以维护容易受到外界所发生的细微变化的影响GRASP模式-高内聚模式(续)GRASP模式-高内聚模式(续)不同功能聚合度的场景(由弱到强)1偶然内聚:指一个模块内的各处理元素之间没有任何联系。2逻辑内聚:指模块内执行几个逻辑上相似的功能,通过参数确定该模块完成哪一个功能。3时间内聚:如果一个模块完成的功能必须在同一时间内执行(如系统初始化),但这些功能只是因为时间因素关联在一起,则称为时间内聚。4通信内聚:指模块内所有处理元素都在同一个数据结构上操作(有时称之为信息内聚),或者指各处理使用相同的输入数据或者产生相同的输出数据。5顺序内聚:指一个模块中各个处理元素都密切相关于同一功能且必须顺序执行,前一功能元素输出就是下一功能元素的输入。6功能内聚:这是最强的内聚,指模块内所有元素共同完成一个功能,缺一不可。与其他模块的耦合是最弱的。电视机,冰箱为什么不做在一起?只需要电视或冰箱功能的消费者却不得不同时购买它们的整合体如果厂家需要升级电视功能,也不得不考虑怎么整合原来的冰箱功能功能低内聚的产品,不利于消费者使用,不利于生产者维护同样,反映到软件设计上,低内聚的类存在使用难,维护升级难的缺点。GRASP模式-高内聚模式(优点)设计的清晰性和易于理解性得到提高。维护和扩展得到简化;常常支持低耦合;重用性提高。GRASP模式-控制器模式