设计模式02-面向对象设计原则.ppt

上传人:qwe****56 文档编号:69530370 上传时间:2023-01-06 格式:PPT 页数:69 大小:637.50KB
返回 下载 相关 举报
设计模式02-面向对象设计原则.ppt_第1页
第1页 / 共69页
设计模式02-面向对象设计原则.ppt_第2页
第2页 / 共69页
点击查看更多>>
资源描述

《设计模式02-面向对象设计原则.ppt》由会员分享,可在线阅读,更多相关《设计模式02-面向对象设计原则.ppt(69页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、设计模式(设计模式(2)p湖北汽车工业学院软件教研室湖北汽车工业学院软件教研室一、类(对象)的职责分配一、类(对象)的职责分配p面向对象的基石是类与对象,如何确定问题域中的类与对象?p类与对象是属性和服务的封装,服务体现了类与对象的职责。如何分配类与对象的职责呢?-GRASP(GeneralResponsibilityAssignmentSoftwarePatterns),通用职责分配软件模式pInformationExpert(信息专家信息专家)-如果某个类拥有完成某个职责所需要的所有信息,那么这个职责就应该分配给这个类来实现。这时,这个类就是相对于这个职责的信息专家。-例如例如:常见的网上

2、商店里的购物车(ShopCar),需要让每种商品(SKU)只在购物车内出现一次,购买相同商品,只需要更新商品的数量即可。如下图:-比较商品是否相同的方法需要放到那里类里来实现呢?分析业务得知需要根据商品的编号(SKUID)来唯一区分商品,而商品编号是唯一存在于商品类里的,所以根据信息专家模式,应该把比较商品是否相同的方法放在商品类里。pCreator(创造者创造者)-如果一个类创建了另一个类,那么这两个类之间就有了耦合,产生了依赖关系。依赖或耦合带来的问题就是在以后的维护中会产生连锁反应,但必要的耦合是逃不掉的,我们能做的就是正确地创建耦合关系,不要随便建立类之间的依赖关系。-凡符合以下条件的

3、情况,都应该由类来创建类,这时是的创建者:是的聚合是的容器持有初始化的信息(数据)记录的实例频繁使用p例如例如:因为订单(Order)是商品(SKU)的容器,所以应该由订单来创建商品。如下图:pLowcoupling(低耦合低耦合)-低耦合意思就是要尽可能地减少类之间的连接。下面这些情况会造成类A、B之间的耦合:A是B的属性A调用B的实例的方法A的方法中引用了B,例如B是A方法的返回值或参数。A是B的子类,或者A实现了B-低耦合降低了因一个类的变化而影响其他类的范围;低耦合使类更容易理解,因为类会变得简单,更内聚。p关于低耦合,有下面一些基本原则:-a.DontTalktoStrangers原

4、则:不需要通信的两个对象之间,不要进行无谓的连接。-如果A已经和B有连接,如果分配A的职责给B不合适的话(违反信息专家模式),那么就把B的职责分配给A。-两个不同模块的内部类之间不能直接连接。-例如例如:Creator模式的例子里,实际业务中需要另一个出货人来清点订单(Order)上的商品(SKU),并计算出商品的总价,但是由于订单和商品之间的耦合已经存在了,那么把这个职责分配给订单更合适,这样可以降低耦合,以便降低系统的复杂性。如下图:pHighcohesion(高内聚)-功能性紧密相关的职责应该放在一个类里,并共同完成有限的功能,那么就是高内聚。这样更有利于类的理解和重用,也便于类的维护。

5、-高内聚也可以说是一种隔离,每一个部分(类)都有自己独立的职责和特性,每一个部分内部发生了问题,也不会影响其他部分,因为高内聚的对象之间是隔离开的。-例如:一个订单数据存取类(OrderDAO),订单即可以保存为Excel模式,也可以保存到数据库中;那么,不同的职责最好由不同的类来实现,这样才是高内聚的设计,如下图:p这里把两种不同的数据存储功能分别放在两个类里来实现,如果未来保存到Excel的功能发生错误,那么检查OrderDAOExcel类就可以了。这使系统模块化,方便划分任务,比如这两个类就可以分配个不同的人同时进行开发,这样也提高了团队协作和开发进度。pController(控制器控制

6、器)-用来接收和处理系统事件的职责,一般应该分配给一个能够代表整个系统的类,这样的类通常被命名为“XX处理器”、“XX协调器”或者“XX会话”。-关于控制器类,有如下原则:a.系统事件的接收与处理通常由一个高级类来代替。b.一个子系统会有很多控制器类,分别处理不同的事务。pPolymorphism(多态多态)-多态更符合高内聚和低耦合原则多态更符合高内聚和低耦合原则-例如例如:设计一个绘图程序,要支持可以画不同类型的图形。先定义一个抽象类Shape,让矩形(Rectangle)、圆形(Round)分别继承这个抽象类,并重写(override)Shape类里的Draw()方法,这样就可以使用同样

7、的接口(Shape抽象类)绘制出不同的图形,如下图:pPureFabrication(纯虚构纯虚构)-高内聚低耦合,是系统设计的终极目标,但是内聚和耦合永远都是矛盾对立的。-高内聚会拆分出更多数量的类,但是对象之间需要协作来完成任务,这又造成了高耦合。-由一个纯虚构的类来协调内聚和耦合,可以在一定程度上解决上述问题。-例如例如:上面多态模式的例子,如果我们的绘图程序需要支持不同的系统,那么因为不同系统的API结构不同,绘图功能也需要不同的实现方式,那么该如何设计更合适呢?如下图:p增加了纯虚构类AbstractShape,不论是哪个系统都可以通过AbstractShape类来绘制图形,我们即没

8、有降低原来的内聚性,也没有增加过多的耦合,pIndirection(间接间接)-“间接”顾名思义,就是这个事不能直接来办,需要绕个弯才行。绕个弯的好处就是,本来直接会连接在一起的对象彼此隔离开了,一个的变动不会影响另一个。-例如“两个不同模块的内部类之间不能直接连接”,但是可以通过中间类来间接连接两个不同的模块,这样对于这两个模块来说,它们之间仍然是没有耦合/依赖关系的。pProtectedVariations(受保护变化受保护变化)-预先找出不稳定的变化点,使用统一的接口封装起来,如果未来发生变化的时候,可以通过接口扩展新的功能,而不需要去修改原来旧的实现。二、可复用面向对象设计的基本原则二

9、、可复用面向对象设计的基本原则p2.1、开闭原则OCP(Open-Closed Principle):-Software entities(classes,-Software entities(classes,modules,functions,etc)modules,functions,etc)should be open for should be open for extension,but closed for extension,but closed for modificationmodification-软件实体(类,模块,函数等)应软件实体(类,模块,函数等)应当对扩展开放,对

10、修改关闭;当对扩展开放,对修改关闭;-理解:理解:撰写软件模块时,应该让它可以扩展,同撰写软件模块时,应该让它可以扩展,同时无须修改。时无须修改。可以改变模块的行为,而不改模块的源代可以改变模块的行为,而不改模块的源代码。码。-OCPOCP原则的基础是抽象,只有抽象才可以抓住原则的基础是抽象,只有抽象才可以抓住事物的本质和共性,保证相对的稳定,实现以事物的本质和共性,保证相对的稳定,实现以不变应万变的功能。不变应万变的功能。-支持支持OCPOCP的技术是抽象、继承、多态、接口。的技术是抽象、继承、多态、接口。-符合该法则便意味着最高等级的复用性符合该法则便意味着最高等级的复用性(reusabi

11、lityreusability)和可维护性)和可维护性(maintainabilitymaintainability)。)。-符合符合OCPOCP的模块标准的模块标准 :可扩展,即可扩展,即“对扩展是开放的对扩展是开放的”(Open Open For ExtensionFor Extension)模块的行为可以被扩)模块的行为可以被扩展,以需要满足新的需求。展,以需要满足新的需求。不可更改,即不可更改,即“对更改是封闭的对更改是封闭的”(Closed for ModificationClosed for Modification)模块)模块的源代码是不允许进行改动的。的源代码是不允许进行改动的

12、。-优越性优越性:通过扩展已有的软件系统,提供新的行通过扩展已有的软件系统,提供新的行为,以满足软件的新需求,使得变化中为,以满足软件的新需求,使得变化中的软件系统有较好的适应性和灵活性;的软件系统有较好的适应性和灵活性;已有的软件模块,特别是抽象层模块不已有的软件模块,特别是抽象层模块不被修改,这就使得变化中的软件就有一被修改,这就使得变化中的软件就有一定的稳定性和灵活性。定的稳定性和灵活性。-说明说明OCPOCP的理想是在不改变源代码的情况下的理想是在不改变源代码的情况下改变模块的功能,这不易实现。改变模块的功能,这不易实现。如果部分的如果部分的OCPOCP实现,也可以戏剧性地实现,也可以

13、戏剧性地改善应用程序的结构。改善应用程序的结构。如果能控制变动不再传播到现有已经可如果能控制变动不再传播到现有已经可以运行的程序代码当中,就很理想了。以运行的程序代码当中,就很理想了。OCPOCP在模式设计中得到广泛的应用。在模式设计中得到广泛的应用。2.2、如何实现开闭原则、如何实现开闭原则2.2.1、针对接口编程,而不是针对(接口的)实现编程-Program To An Interface,Not An Implementationp接口的定义接口的定义-对象声明的每一个方法所指定的方法名、参数和对象声明的每一个方法所指定的方法名、参数和返回值构成了对象的方法签名返回值构成了对象的方法签名

14、(signature(signature)。)。-对象方法所定义的所有方法签名的集合被称为该对象方法所定义的所有方法签名的集合被称为该对象的接口(对象的接口(interfaceinterface),它描述了该对象所能),它描述了该对象所能接受的全部请求的集合。接受的全部请求的集合。-在面向对象系统中,对象只通过接口与外部交流。在面向对象系统中,对象只通过接口与外部交流。对象接口与其功能实现是分离的,两个有相同接对象接口与其功能实现是分离的,两个有相同接口的对象可以有完全不同的实现。口的对象可以有完全不同的实现。-对应程序设计语言中对应程序设计语言中interface/abstract clas

15、sinterface/abstract class。-从接口导出的子类有如下特点:从接口导出的子类有如下特点:子类仅仅添加或重定义操作,而没子类仅仅添加或重定义操作,而没有隐藏父类的操作。有隐藏父类的操作。所有的子类都能响应接口中的请求,所有的子类都能响应接口中的请求,子类的类型都是接口的子类型。子类的类型都是接口的子类型。p实施原则-不将变量声明为某个特定的具体类的实例对象,而声明为抽象类所定义的接口。-当不得不在系统的某个地方实例化具体的类时,可应用创建型模式(Abstract Factory,Builder,Factory Method,Prototype和Singleton)。-创建型

16、模式确保系统是采用针对接口的方式书写的,而不是针对实现而书写的。p好处好处:-1)客户无须知道所使用对象的特定类型,只须对象有客户所期望的接口;-2)客户无须知道所使用的对象是用什么类来实现的,只须知道定义接口的抽象类。-3)降低程序各部分之间的耦合性,使程序模块互换成为可能。例子例子pPublic interface IManeuverablePublic void left();public void right();Public void forward();public void reverse();public void setSpeed(double speed);Public f

17、loat getSpeed();ppPublic class Car implements IManeuverable-/ppPublic class Boat implements IManeuverable-/ppIManeuverableIman=newCar();pIman.setspeed();2.2.2、优先使用对象组合,而不是类继承p英文原意:英文原意:-Favorobjectcompositionoverclassinheritance.p什么是组合(什么是组合(compositioncomposition)-是一种通过创建一个是一种通过创建一个组合组合了其它对象的对象,从而获

18、了其它对象的对象,从而获得新功能的复用方法。得新功能的复用方法。-包括聚合(包括聚合(aggregationaggregation)和包容()和包容(containmentcontainment)两)两种特殊形式。种特殊形式。聚合标识拥有关系(聚合标识拥有关系(has a),has a),如运动员与运动队。如运动员与运动队。包容是强烈的拥有关系,拥有者负责被拥有者的生包容是强烈的拥有关系,拥有者负责被拥有者的生命周期,如汽车与轮胎关系。命周期,如汽车与轮胎关系。p组合与继承的比较组合与继承的比较-联系联系组合以及继承的目的都是为了复用。组合以及继承的目的都是为了复用。-区别区别继承是一种通过扩

19、展一个已有对象的实继承是一种通过扩展一个已有对象的实现,从而获得新功能的复用方法;现,从而获得新功能的复用方法;组合使得原有对象成为新对象的一部分,组合使得原有对象成为新对象的一部分,因此新的对象可以调用已有对象的功能。因此新的对象可以调用已有对象的功能。p组合的优点:组合的优点:-因为对象只能通过接口访问,所以组合并不破坏因为对象只能通过接口访问,所以组合并不破坏封装性;封装性;-因为对象的实现是基于接口写的只要类型一致,因为对象的实现是基于接口写的只要类型一致,运行时刻可以用一个对象来替代另一个对象,所运行时刻可以用一个对象来替代另一个对象,所以实现上存在较少的依赖关系。以实现上存在较少的

20、依赖关系。-优先使用对象组合有助于保持每个类被封装,并优先使用对象组合有助于保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞持较小规模,并且不太可能增长为不可控制的庞然大物。然大物。-基于对象组合的设计将使系统的行为依赖于对象基于对象组合的设计将使系统的行为依赖于对象间的关系而不是被定义在某个类中。间的关系而不是被定义在某个类中。p组合的缺点:组合的缺点:-会有较多的对象需要管理。-为了能将多个不同的对象作为组合块来使用,必须仔细地对接口进行定义。p继承的优点:继承的优点:-因为大部分功能可以通过

21、继承关系自动进入子类,所以新的实现较为容易。-继承使修改或者扩展继承来的实现较为容易。p继承的缺点:继承的缺点:-因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。-父类通常至少定义了部分子类的具体表示,由于子类能揭示其父类的实现细节,所以继承常被认为“破坏了封装性”。-子类中的实现与它的父类有紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。-复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。-一个可用的解决方法-只继承抽象类,因为抽象类通常提供较少的实现。p如何应用这条原则-

22、理想情况下,不应为获得复用而去创建新的构件。-应该尽可能只使用对象组合技术,通过组装已有的构件就能获得需要的功能。-使用继承的复用使得创建新的构件要比组装旧的构件来得容易。实践中继承和对象组合常一起使用。2.2.32.2.3、封装变化点、封装变化点p英文英文-encapsulating the concept that varies(GOF)p含义:含义:-将系统中经常变化的部分封装起来,以和稳定的部将系统中经常变化的部分封装起来,以和稳定的部分隔离。分隔离。p理解理解-使用封装来创建对象之间的分界层,让设计者可以使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一

23、侧产生不在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。良的影响,从而实现层次间的松耦合。-获得最大限度复用的关键在于对新需求和已有需求获得最大限度复用的关键在于对新需求和已有需求发生变化时的预见性,这就要求系统要能够封装变发生变化时的预见性,这就要求系统要能够封装变化点,以减少系统重新设计的机会。化点,以减少系统重新设计的机会。p评价:评价:-有助于增加复用性,并降低系统耦合有助于增加复用性,并降低系统耦合度。度。-基于设计模式的解决方案擅长封装变基于设计模式的解决方案擅长封装变化点。化点。三、可复用面向对象设计的一般原则三、可复用面向对象设计的一般原则p1 1

24、、单一职责原则(、单一职责原则(SRPSRP)p2 2、LiskovLiskov 替换原则(替换原则(LSPLSP)p3 3、依赖倒置原则(、依赖倒置原则(DIPDIP)p4 4、接口隔离原则(接口隔离原则(ISPISP)p5 5、迪米特原则、迪米特原则3.1单一职责原则(单一职责原则(SRP)p SRPSRP(Single-Responsibility Principle Single-Responsibility Principle)含义:)含义:-A A CalssCalss should have only one should have only one reason to reas

25、on to changgechangge。-一个类应该仅有一个原因导致其变化。一个类应该仅有一个原因导致其变化。p理解理解-如果一个类包含过多的职责,这就意味着如果一个类包含过多的职责,这就意味着会有多个导致其变化的原因。而且,这些会有多个导致其变化的原因。而且,这些变化往往不是孤立的,它们通过多个职责变化往往不是孤立的,它们通过多个职责间的耦合关系相互作用,使类产生多个互间的耦合关系相互作用,使类产生多个互相依赖的不确定的演化方向,带来维护和相依赖的不确定的演化方向,带来维护和重用上的困难。重用上的困难。-按单一职责分解系统,是否会造成类过多按单一职责分解系统,是否会造成类过多?注意分解的粒

26、度。注意分解的粒度。控制分解的标准是控制分解的标准是“变化变化”,把那些多,把那些多边或易变的部分分离出去。边或易变的部分分离出去。3.3Liskov替换原则(替换原则(LSP)pLSP(LiskovLSP(Liskov Substitution Principle)Substitution Principle)含义含义-Subtype must be substitutable for Subtype must be substitutable for their base type their base type。-派生类应该可以替换基类。派生类应该可以替换基类。-Function Tha

27、t Use Function That Use ReferenncesReferennces To To Base(SuperBase(Super)Classes Must Be Able To)Classes Must Be Able To Use Objects Of Use Objects Of Derived(SubDerived(Sub)Classes)Classes Without Knowing It Without Knowing It。-使用指向基类(超类)的引用的函数,必使用指向基类(超类)的引用的函数,必须能够在不知道具体派生类(子类)对象须能够在不知道具体派生类(子类)

28、对象类型的情况下使用它们。类型的情况下使用它们。p理解:理解:-如果在用户的某些方法中,使用基类作为如果在用户的某些方法中,使用基类作为参数,则应该允许在方法中传入派生类对参数,则应该允许在方法中传入派生类对象的实例。象的实例。-LisKovLisKov代换法则利用了类型继承关系中的代换法则利用了类型继承关系中的向上转型机制(向上转型是安全的)。向上转型机制(向上转型是安全的)。-LSPLSP保证一个子类总是能够被用在其基类可保证一个子类总是能够被用在其基类可以出现的地方。以出现的地方。p理氏代换原则是继承复用的基石,只有衍生类可以替理氏代换原则是继承复用的基石,只有衍生类可以替换基类,软件单

29、位不受到影响,基类才能被真正复用,换基类,软件单位不受到影响,基类才能被真正复用,而衍生类也才能在基类的基础上增加新的行为。而衍生类也才能在基类的基础上增加新的行为。p注意:反过来并不成立,一个软件实体如果使用的是注意:反过来并不成立,一个软件实体如果使用的是一个子类的话,不应定适用于基类。一个子类的话,不应定适用于基类。3.4依赖倒置原则(依赖倒置原则(DIP)pDIPDIP(Dependency Inversion Principle)Dependency Inversion Principle)含义:含义:-Abstractions should not depend on detail

30、s,Details should depend on abstractions。-抽象不应该依赖于实现细节,实现细节应该依赖于抽象。p理解理解-依赖倒置原则强调依赖接口、抽象方法及抽象类,而不是依赖具体方法或类。p理解理解-结构化设计中,高层模块依赖于底层模块,结构化设计中,高层模块依赖于底层模块,抽象层依赖于具体层,从而形成由上到下顺抽象层依赖于具体层,从而形成由上到下顺序依赖的架构设计,这种结构从顶部主模块序依赖的架构设计,这种结构从顶部主模块开始,然后向下发展出细节部分。存在着弱开始,然后向下发展出细节部分。存在着弱点:点:底层模块实现的是具体细节,这就决定了它的多底层模块实现的是具体细

31、节,这就决定了它的多变。如果总是向下依赖于多变的下级模块,必然变。如果总是向下依赖于多变的下级模块,必然会把这种变化不定的因素传播到上层,影响系统会把这种变化不定的因素传播到上层,影响系统得稳定性和健壮性。得稳定性和健壮性。虽然通过增加中间层的努力可以吸收底层变化因虽然通过增加中间层的努力可以吸收底层变化因素,但中间层并不能改变这种顺序依赖,相反,素,但中间层并不能改变这种顺序依赖,相反,中间层的加入反而又导致了上层对中间层的依赖,中间层的加入反而又导致了上层对中间层的依赖,增加了系统的复杂性。增加了系统的复杂性。高级商业逻辑中间层模块底层模块中间层模块中间层模块中间层模块底层模块底层模块底层

32、模块错错误误的的依依赖赖方方向向-倒置的原则扭转上述错误的依赖关系,抽象层次包含的是应用系统的业务逻辑和宏观的、对整个系统来说重要的战略性决定,是必然的体现,而具体层次则要实现有关的算法和逻辑,以及战术的决定,带有相当大的偶然性,会经常变化。高级商业逻辑抽象层具体层抽象层抽象层抽象层具体层具体层具体层错错误误的的依依赖赖方方向向正正确确的的依依赖赖方方向向-面向对象的架构中,高层模块不再依赖面向对象的架构中,高层模块不再依赖于含有实现细节的模块,而是依赖抽象于含有实现细节的模块,而是依赖抽象的接口。这种设计的好处是的接口。这种设计的好处是:通过抽象接口取代被依赖的中间层,通过抽象接口取代被依赖

33、的中间层,保证了上层结构的稳定。因为底层保证了上层结构的稳定。因为底层细节实现模块的变化并不导致接口细节实现模块的变化并不导致接口的改变。的改变。也就是说,同一接口允许有不同的也就是说,同一接口允许有不同的实现方法,甚至不同的实现模块。实现方法,甚至不同的实现模块。p如何应用这一原则如何应用这一原则-设计中的每一个依赖关系,应该是依赖于接设计中的每一个依赖关系,应该是依赖于接口,或一个抽象类,而不是一个具体类。口,或一个抽象类,而不是一个具体类。抽象的东西比较稳定。能使我们有更多的回旋余抽象的东西比较稳定。能使我们有更多的回旋余地。地。抽象层可以作为上下层之间的枢纽,代表设计中抽象层可以作为上

34、下层之间的枢纽,代表设计中可以伸缩或扩展的地方,而且在变动时不致于被可以伸缩或扩展的地方,而且在变动时不致于被修改,从而达到修改,从而达到OCPOCP的要求。的要求。-在可能的情况下,这个法则应该尽可能遵循,在可能的情况下,这个法则应该尽可能遵循,至少组件一定要遵循这个法则。如至少组件一定要遵循这个法则。如COMCOM就坚持就坚持这个法则。这个法则。COMCOM组件唯一可以看到的部分就是组件唯一可以看到的部分就是其抽象的接口。其抽象的接口。-在设计中常发生依赖具体类的地方是建构在设计中常发生依赖具体类的地方是建构对象。在架构设计中的任何地方都可能发对象。在架构设计中的任何地方都可能发生构造对象

35、实例的情况。抽象工厂模式是生构造对象实例的情况。抽象工厂模式是解决这个问题的一个简单方法。解决这个问题的一个简单方法。-在多层系统的设计中,通过代理模式引入在多层系统的设计中,通过代理模式引入的代理层,可以使得原来相互依赖的层之的代理层,可以使得原来相互依赖的层之间实现依赖反转,从而满足层与层之间独间实现依赖反转,从而满足层与层之间独立演化的需求。特别在业务层依赖数据层立演化的需求。特别在业务层依赖数据层或其他第三方中间层时,这种设计可以很或其他第三方中间层时,这种设计可以很好的消除耦合。好的消除耦合。3.5 3.5 接口隔离原则(接口隔离原则(ISPISP)pISPISP(Interface

36、 Segregation PrincipleInterface Segregation Principle)含义含义:-Clients should not be forced to Clients should not be forced to depend on methods that they do depend on methods that they do not use.not use.-不应该强迫客户程序依赖于它们不用不应该强迫客户程序依赖于它们不用的方法。的方法。-每一个接口都应该是一种角色,不要每一个接口都应该是一种角色,不要干不该干不要强迫客户依赖于它们不干不该干不要强迫

37、客户依赖于它们不用的方法。用的方法。p理解-依据不同的客户端而划分出多个不同的专用接口,比使用单一的总接口好。-如果客户程序依赖于那些有它们不使用的方法的类,当其他客户要求这个类改变时,就会影响到这个客户程序,这无意中导致了所有客户程序之间的耦合。由于希望尽可能地避免这种耦合,因此希望分离接口。-接口是对客户端的一种开发的承诺,一种通信的协议,一种服务的契约,一旦公布很难收回。一个反面例子一个反面例子一个正面例子一个正面例子p关于接口常遇到的问题-合并接口:把多个功能相近的不同接口合并成一个大接口。这样看上去总的接口数量减少了,但针对不同的客户端而言,它们却要面向大接口中大量冗余的,用不着的方

38、法,使得接口臃肿,难以理解。-预留接口:设计时预留接口,为以后系统的变更和扩展做考虑。结果可能给系统留下了一大块垃圾,徒增系统的维护成本。p接口设计原则接口设计原则-以客户端的需求划分接口。以客户端的需求划分接口。-即使两个不同类型的客户端需要相同即使两个不同类型的客户端需要相同的方法,也要增加接口。的方法,也要增加接口。-通过设计原则通过设计原则LSP、DIP而不是通过而不是通过预留接口来增加系统的可扩展性。预留接口来增加系统的可扩展性。-推荐使用抽象接口,给现有对象增加推荐使用抽象接口,给现有对象增加接口而不是修改接口。接口而不是修改接口。3.6迪米特法则迪米特法则pLoD(Law of

39、Demeter),1987年秋天Ian Holland在美国东北大学为一个叫迪米特的项目做设计时提出。又叫最少知识原则(Least Knowledge Principle)-Only talk to your immediate friends只与你直接的朋友们通信-Dont Talk to strangers不要跟“陌生人”说话-每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。n狭义的迪米特法则:n如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另外一个类的某一个方法,可以通过第三者转发这个调用。pFriend

40、Friend类持有一个类持有一个StrangerStranger类的私有对象,他类的私有对象,他们是朋友类:们是朋友类:ppublicpublicclassclassFriendFriend privateprivateStrangerStrangerstrangerstranger=newnewStrangeStranger()r();publicpublicvoidvoidoperation2()operation2()publicpublicStrangerStrangerprovide()provide()returnreturnstrangerstranger;p pSomeone类

41、有一个方法接受一个Friend类型的变量,但直接与Stranger类通信:ppublicpublicclassclassSomeone Someone publicpublicvoidvoidoperation1(operation1(FriendFriendfriendfriend)StrangerStrangerstrangerstranger=friend.providefriend.provide()();stranger.operation3()stranger.operation3();p p不符合迪米特法则不符合迪米特法则p改造,首先在Friend类里添加一个方法,封装对Stra

42、nger类的操作:ppublicpublicclassclassFriend Friend privateprivateStrangerStrangerstrangerstranger=newnewStranger()Stranger();publicpublicvoidvoidoperation2()operation2()publicpublicStrangerStrangerprovide()provide()returnreturnstrangerstranger;publicpublicvoidvoidforward()forward()stranger.operation3()st

43、ranger.operation3();p p然后,我们重构然后,我们重构SomeoneSomeone的的operation1operation1方法,让其调用新提供的方法,让其调用新提供的forwardforward方法:方法:-publicpublicclassclassSomeoneSomeone publicpublicvoidvoidoperation1(operation1(FriendFriendfriendfriend)friend.forwardfriend.forward()();p现在Someone对Stranger的依赖完全通过Friend隔离,这样的结构已经符合狭义迪

44、米特法则了。p狭义迪米特法则一个明显的缺点:会在系统里造出大量的小方法,散落在系统的各个角落。这些小的方法会造成设计师的迷惑和困扰。p遵循迪米特法则会使一个系统的局部设计简化,也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。p结合依赖倒转原则,对代码进行如下重构来解决这个结合依赖倒转原则,对代码进行如下重构来解决这个问题,首先添加一个抽象的问题,首先添加一个抽象的StrangerStranger类,使类,使SomeoneSomeone依依赖于抽象的赖于抽象的“StrangerStranger”角色,而不是具体实现:角色,而不是具体实现:-publicpublica

45、bstract class abstract class AbstractStrangerAbstractStranger abstractabstractvoidvoidoperation3()operation3();p然后,让然后,让StrangerStranger从该类继承:从该类继承:-publicpublicclassclassStrangerStrangerextendsextendsAbstractSAbstractStrangertranger publicpublicvoidvoidoperation3()operation3()p随后,重构随后,重构SomeoneSome

46、one使其依赖抽象的使其依赖抽象的StrangerStranger角色:角色:ppublicpublicclassclassSomeone Someone publicpublicvoidvoidoperation1(operation1(FriendFriendfriendfriend)AbstractStrangerAbstractStrangerstrangerstranger=friend.providefriend.provide()();stranger.operation3()stranger.operation3();p最后,重构最后,重构FriendFriend的的provi

47、deprovide方法,使其返回抽象角方法,使其返回抽象角色:色:ppublicpublicclassclassFriend Friend privateprivateStrangerStrangerstrangerstranger=newnewStranger()Stranger();publicpublicvoidvoidoperation2()operation2()publicpublicAbstractStrangerAbstractStrangerprovide()provide()returnreturnstrangerstranger;p 现在,现在,AbstractStran

48、gerAbstractStranger成为成为SomeoneSomeone的朋友类,的朋友类,而而FriendFriend类可以随时替换掉类可以随时替换掉AbstractStrangerAbstractStranger的的实现类,实现类,SomeoneSomeone不再需要了解不再需要了解StrangerStranger的内部的内部实现细节。下图是重构后的实现细节。下图是重构后的UMLUML类图:类图:p广义迪米特法则广义迪米特法则-在类的划分上,应该创建有弱耦在类的划分上,应该创建有弱耦合的类;合的类;-在类的结构设计上,每一个类都在类的结构设计上,每一个类都应当尽量降低成员的访问权限;应当

49、尽量降低成员的访问权限;-在类的设计上,只要有可能,一在类的设计上,只要有可能,一个类应当设计成不变类;个类应当设计成不变类;-在对其他类的引用上,一个对象对其它对象的引用应当降到最低;-尽量降低类的访问权限;-谨慎使用序列化功能;-不要暴露类成员,而应该提供相应的访问器(属性)。本章作业本章作业p2.12.1、面向对象设计的基本原则是什么?如何、面向对象设计的基本原则是什么?如何实施这个原则?实施这个原则?p2.22.2、面向对象设计的一般原则有哪些?谈谈、面向对象设计的一般原则有哪些?谈谈你对相关原则的理解。你对相关原则的理解。p2.32.3、查阅资料,阐述、查阅资料,阐述GRASPGRASP模式。模式。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 应用文书 > 财经金融

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com