合成聚合复用原则

合集下载

软件体系结构与设计模式期末复习

软件体系结构与设计模式期末复习

体系结构期末复习一、选择题(一)1. 设计模式的基本原理是( C )A. 面向实现编程B. 面向对象编程C. 面向接口编程D. 面向组合编程2. 设计模式的两大主题是( D )A. 系统的维护与开发B. 对象组合与类的继承C. 系统架构与系统开发D. 系统复用与系统扩展3. 依据设计模式思想,程序开发中应优先使用的是( A )关系实现复用。

A. 组合聚合B. 继承C. 创建D. .以上都不对4. 关于继承表述错误的是( D )A. 继承是一种通过扩展一个已有对象的实现,从而获得新功能的复用方法。

B. 泛化类(超类)可以显式地捕获那些公共的属性和方法。

特殊类(子类)则通过附加属性和方法来进行实现的扩展。

C. 破坏了封装性,因为这会将父类的实现细节暴露给子类。

D. 继承本质上是“白盒复用”,对父类的修改,不会影响到子类。

5. 常用的设计模式可分为( A )A. 创建型、结构型和行为型B. 对象型、结构型和行为型C. 过程型、创建型和结构型D. 抽象型、接口型和实现型6. “不要和陌生人说话”是对( D )设计原则的通俗表述。

A. 接口隔离B. 里氏代换C. 依赖倒转D. .迪米特法则7. 在适配器模式中,对象适配器模式是对( A )设计原则的典型应用A. 合成聚合B. 里氏代换C. 依赖倒转D. .迪米特法则8. 将一个类的接口转换成客户希望的另一个接口,这句话是对(C)设计模式的描述A. 策略模式B. 桥接模式C. 适配器模式D. 单例模式9. 以下设计模式中属于结构模式的是( D )A. 观察者模式B. 单例模式C. 策略模式D. 外观模式10. 以下不属于对象行为型模式是( D )A. 命令模式B. 策略模式C. 访问者模式D. 桥接模式11. 下面的类图表示的是哪个设计模式( D )A. 抽象工厂模式B. 观察者模式C. 策略模式D. 桥接模式12. Open-Close开闭原则的含义是一个软件实体( A )A. 应当对扩展开放,对修改关闭。

OO设计原则

OO设计原则

OO设计原则在软件软件系统中,一个模块设计得好不好的最主要、最重要的标志,就是该模块在多大程度上将自己的内部数据和其他与实现有关的细节隐藏起来。

一个设计得好的模块可以将它所有的实现细节隐藏起来,彻底地将提供给外界的API和自己的实现分隔开来。

这样一来,模块与模块之间就可以仅仅通过彼此的API相互通信,而不理会模块内部的工作细节。

OO设计根本的指导原则是提高可维护性和可复用性。

这些原则主要有:1. 开闭原则一个软件实体应该对扩展开放,对修改关闭。

在设计一个模块的时候,就当使这个模块可以在不被修改的前提下被扩展。

换言之,就当可以在不必修改源代码的情况下改变这个模块的行为。

如何做到既不修改,又可以扩展?解决问题的关键在于抽象化:在Java语言里,可以给出一个或多个抽象Java类或Java接口,规定出所有的具体类必须提供的方法特征作为系统设计的抽象层。

这个抽象层预见了所有的可能扩展,因此,在任何扩展情况下都不会改变。

这就使得系统的抽象层不需要修改,从而满足了—对修改关闭。

同时,由于从抽象层导出一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的。

开闭原则实际上是对“对可变性的封闭原则“:找到一个系统的可变因素,将之封装起来。

这个原则意昧着两点:1) 一个可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。

同一种可变性的不同表象意昧着同一个继承等级结构中的具体子类。

继承就当被看作是封装变化的方法,而不应当被认为是从一般的对象生成特殊对象的方法。

2) 一种可变性不应当与另一种可变性混合在一起。

(所有类图的继承结构一般不会超过两层,不然就意昧着将两种不同的可变性混合在了一起。

)开闭原则是总的原则,其它几条是开闭原则的手段和工具。

2. 依赖倒转原则依赖倒转原则讲的是:要依赖于抽象,不要信赖于实现。

开闭原则是目标,而达到这一目标的手段是依赖倒转原则。

抽象层次包含的是应用系统的商务逻辑和宏观的、对整个系统来说重要的战略性决定,是必然性的体现;而具体层次则含有一些次要的与实现有关的算法和逻辑,以及战术性的决定,带有相当大的偶然性选择。

程序设计七大原则

程序设计七大原则

软件设计的七大原则设计模式遵循的一般原则:1.开-闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开发,对修改关闭.说的是,再设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展.换言之,应当可以在不必修改源代码的情况下改变这个模块的行为,在保持系统一定稳定性的基础上,对系统进行扩展。

这是面向对象设计(OOD)的基石,也是最重要的原则。

2.里氏代换原则(Liskov Substitution Principle,常缩写为.LSP)(1).由Barbar Liskov(芭芭拉.里氏)提出,是继承复用的基石。

(2).严格表达:如果每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换称o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型.换言之,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别.只有衍生类可以替换基类,软件单位的功能才能不受影响,基类才能真正被复用,而衍生类也能够在基类的基础上增加新功能。

(3).反过来的代换不成立(4).<墨子.小取>中说:"白马,马也; 乘白马,乘马也.骊马(黑马),马也;乘骊马,乘马也."(5).该类西方著名的例程为:正方形是否是长方形的子类(答案是"否")。

类似的还有椭圆和圆的关系。

(6).应当尽量从抽象类继承,而不从具体类继承,一般而言,如果有两个具体类A,B有继承关系,那么一个最简单的修改方案是建立一个抽象类C,然后让类A和B 成为抽象类C的子类.即如果有一个由继承关系形成的登记结构的话,那么在等级结构的树形图上面所有的树叶节点都应当是具体类;而所有的树枝节点都应当是抽象类或者接口.(7)."基于契约设计(Design By Constract),简称DBC"这项技术对LISKOV代换原则提供了支持.该项技术Bertrand Meyer伯特兰做过详细的介绍:使用DBC,类的编写者显式地规定针对该类的契约.客户代码的编写者可以通过该契约获悉可以依赖的行为方式.契约是通过每个方法声明的前置条件(preconditions)和后置条件(postconditions)来指定的.要使一个方法得以执行,前置条件必须为真.执行完毕后,该方法要保证后置条件为真.就是说,在重新声明派生类中的例程(routine)时,只能使用相等或者更弱的前置条件来替换原始的前置条件,只能使用相等或者更强的后置条件来替换原始的后置条件.3.依赖倒置原则(Dependence Inversion Principle),要求客户端依赖于抽象耦合.(1)表述:抽象不应当依赖于细节,细节应当依赖于抽象.(Program to an interface, not an implementaction)(2)表述二:针对接口编程的意思是说,应当使用接口和抽象类进行变量的类型声明,参量的类型声明,方法的返还类型声明,以及数据类型的转换等.不要针对实现编程的意思就是说,不应当使用具体类进行变量的类型声明,参量类型声明,方法的返还类型声明,以及数据类型的转换等.要保证做到这一点,一个具体的类应等只实现接口和抽象类中声明过的方法,而不应当给出多余的方法.只要一个被引用的对象存在抽象类型,就应当在任何引用此对象的地方使用抽象类型,包括参量的类型声明,方法返还类型的声明,属性变量的类型声明等. (3)接口与抽象的区别就在于抽象类可以提供某些方法的部分实现,而接口则不可以,这也大概是抽象类唯一的优点.如果向一个抽象类加入一个新的具体方法,那么所有的子类型一下子就都得到得到了这个新的具体方法,而接口做不到这一点.如果向一个接口加入了一个新的方法的话,所有实现这个接口的类就全部不能通过编译了,因为它们都没有实现这个新声明的方法.这显然是接口的一个缺点.(4)一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的登记结构中,而由于一般语言都限制一个类只能从最多一个超类继承,因此将抽象作为类型定义工具的效能大打折扣.反过来,看接口,就会发现任何一个实现了一个接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个接口.(5)从代码重构的角度上讲,将一个单独的具体类重构成一个接口的实现是很容易的,只需要声明一个接口,并将重要的方法添加到接口声明中,然后在具体类定义语句中加上保留字以继承于该接口就行了.而作为一个已有的具体类添加一个抽象类作为抽象类型不那么容易,因为这个具体类有可能已经有一个超类.这样一来,这个新定义的抽象类只好继续向上移动,变成这个超类的超类,如此循环,最后这个新的抽象类必定处于整个类型等级结构的最上端,从而使登记结构中的所有成员都会受到影响.(6)接口是定义混合类型的理想工具,所为混合类型,就是在一个类的主类型之外的次要类型.一个混合类型表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为.(7)联合使用接口和抽象类:由于抽象类具有提供缺省实现的优点,而接口具有其他所有优点,所以联合使用两者就是一个很好的选择.首先,声明类型的工作仍然接口承担的,但是同时给出的还有一个抽象类,为这个接口给出一个缺省实现.其他同属于这个抽象类型的具体类可以选择实现这个接口,也可以选择继承自这个抽象类.如果一个具体类直接实现这个接口的话,它就必须自行实现所有的接口;相反,如果它继承自抽象类的话,它可以省去一些不必要的的方法,因为它可以从抽象类中自动得到这些方法的缺省实现;如果需要向接口加入一个新的方法的话,那么只要同时向这个抽象类加入这个方法的一个具体实现就可以了,因为所有继承自这个抽象类的子类都会从这个抽象类得到这个具体方法.这其实就是缺省适配器模式(Defaule Adapter).(8)什么是高层策略呢?它是应用背后的抽象,是那些不随具体细节的改变而改变的真理. 它是系统内部的系统____隐喻.4.接口隔离原则(Interface Segregation Principle, ISP) (1)一个类对另外一个类的依赖是建立在最小的接口上。

合成复用原则、迪米特法则

合成复用原则、迪米特法则

合成复用原则、迪米特法则
合成复用原则和迪米特法则都是面向对象编程中的基本原则,它们有助于创建高效、可维护和可扩展的软件系统。

合成复用原则(Composite Reuse Principle):该原则主张尽量使用合成/聚合的方式,而不是使用继承。

这意味着将对象组合成新的对象,而不是通过继承来创建新类。

通过将对象组合在一起,可以更容易地修改和扩展系统,同时避免破坏现有代码。

此外,合成复用原则还强调每个组件都应该有明确定义的职责,这有助于提高代码的可读性和可维护性。

迪米特法则(Demeter Principle):也称为最少知道原则,它指出一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

这意味着一个对象应该只与直接的朋友通信,而不是与其他不相关的对象通信。

这有助于降低对象之间的耦合度,提高系统的可维护性和可扩展性。

同时,迪米特法则还鼓励将逻辑封装在类的内部,对外除了提供的 public 方法,不对外泄露任何信息。

这样可以提高代码的安全性和稳定性,减少外部对内部实现的干扰。

总之,合成复用原则和迪米特法则都是面向对象编程中的重要原则,它们有助于创建高效、可维护和可扩展的软件系统。

通过遵循这些原则,可以提高代码的可读性、可维护性和可扩展性。

可复用构件设计的原则

可复用构件设计的原则

论文题目:可复用构件设计的原则院(系): 研究生学院专业年级: 计算机科学与技术**: ***学号: *************: ***2014年4月29日一、开闭原则1988年,Bertrand Meyer在他的著作《Object Oriented Software Construction》中提出了开闭原则,原文为:“Software entities should be open for extension,but closed for modification”。

即“软件实体应当对扩展开放,对修改关闭”。

即软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。

开闭原则中的“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中的“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。

实现开闭原则的关键就在于“抽象”。

把系统的所有可能的行为抽象成一个抽象底层,这个抽象底层规定出所有的具体实现必须提供的方法的特征。

作为系统设计的抽象层,要预见所有可能的扩展,从而使得在任何扩展情况下,系统的抽象底层不需修改;同时,由于可以从抽象底层导出一个或多个新的具体实现,可以改变系统的行为,因此系统设计对扩展是开放的。

在软件开发的过程中,一直都是提倡需求导向的。

这就要求在设计的时候,要非常清楚地了解用户需求,判断需求中包含的可能的变化,从而明确在什么情况下使用开闭原则。

关于系统可变的部分,还有一个更具体的原则是对可变性的封装原则(Principle of Encapsulation of Variation, EVP),它从软件工程实现的角度对开闭原则进行了进一步的解释。

EVP要求在做系统设计的时候,对系统所有可能发生变化的部分进行评估和分类,每一个可变的因素都单独进行封装。

“对可变性的封装原则”意味着两点:(1)一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。

面向对象设计七大原则

面向对象设计七大原则

⾯向对象设计七⼤原则1. 单⼀职责原则(Single Responsibility Principle)每⼀个类应该专注于做⼀件事情。

2. ⾥⽒替换原则(Liskov Substitution Principle)超类存在的地⽅,⼦类是可以替换的。

3. 依赖倒置原则(Dependence Inversion Principle)实现尽量依赖抽象,不依赖具体实现。

4. 接⼝隔离原则(Interface Segregation Principle)应当为客户端提供尽可能⼩的单独的接⼝,⽽不是提供⼤的总的接⼝。

5. 迪⽶特法则(Law Of Demeter)⼜叫最少知识原则,⼀个软件实体应当尽可能少的与其他实体发⽣相互作⽤。

6. 开闭原则(Open Close Principle)⾯向扩展开放,⾯向修改关闭。

7. 组合/聚合复⽤原则(Composite/Aggregate Reuse Principle CARP)尽量使⽤合成/聚合达到复⽤,尽量少⽤继承。

原则:⼀个类中有另⼀个类的对象。

细则单⼀职责原则(Single Responsibility Principle)因为:可以降低类的复杂度,⼀个类只负责⼀项职责,其逻辑肯定要⽐负责多项职责简单的多;提⾼类的可读性,提⾼系统的可维护性;变更引起的风险降低,变更是必然的,如果单⼀职责原则遵守的好,当修改⼀个功能时,可以显著降低对其他功能的影响。

需要说明的⼀点是单⼀职责原则不只是⾯向对象编程思想所特有的,只要是模块化的程序设计,都适⽤单⼀职责原则。

所以:从⼤局上看Android中的Paint和Canvas等类都遵守单⼀职责原则,Paint和Canvas各司其职。

⾥⽒替换原则(Liskov Substitution Principle)因为:⾥⽒替换原则告诉我们,在软件中将⼀个基类对象替换成它的⼦类对象,程序将不会产⽣任何错误和异常,反过来则不成⽴,如果⼀个软件实体使⽤的是⼀个⼦类对象的话,那么它不⼀定能够使⽤基类对象。

合成聚合复用原则

合成聚合复用原则

合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)合成(Composition)和聚合(Aggregation)都是关联(Association)的特殊种类。

聚合表示整体和部分的关系,表示“拥有”。

如奔驰S360汽车,对奔驰S360引擎、奔驰S360轮胎的关系是聚合关系,离开了奔驰S360汽车,引擎、轮胎就失去了存在的意义。

在设计中,聚合不应该频繁出现,这样会增大设计的耦合度。

合成则是一种更强的“拥有”,部分和整体的生命周期一样。

合成的新的对象完全支配其组成部分,包括它们的创建和湮灭等。

一个合成关系的成分对象是不能与另一个合成关系共享的。

换句话说,合成是值的聚合(Aggregation by Value),而一般说的聚合是引用的聚合(Aggregation by Reference)。

在面向对象设计中,有两种基本的办法可以实现复用:第一种是通过合成/聚合,即合成复用原则,含义是指,尽量使用合成/聚合,而不是使用继承。

第二种就是通过继承。

要正确地选择合成/复用和继承的方法是,只有当以下的条件全部被满足时,才应当使用继承关系:1)子类是父类的一个特殊种类,而不是父类的一个角色,也就是区分"Has-A"和"Is-A"。

只有"Is-A"关系才符合继承关系,"Has-A"关系应当用聚合来描述。

2)永远不会出现需要将子类换成另外一个类的子类的情况。

如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。

3)子类具有扩展父类的责任,而不是具有置换掉(override)或注销掉(Nullify)父类的责任。

如果一个子类需要大量的置换掉父类的行为,那么这个类就不应该是这个父类的子类。

4)只有在分类学角度上有意义时,才可以使用继承。

如果语义上存在着明确的is-a关系,并且这种关系是稳定的、不变的,则考虑使用继承;如果没有is-a关系,或者这种关系是可变的,使用合成。

面向对象七大基本设计原则

面向对象七大基本设计原则

面向对象七大基本设计原则面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心。

在设计面向对象的程序的时,模式不是一定要套的,但是有一些原则最好是遵守。

这些原则已知的有七个,包括:单一职责原则、开闭原则、里氏代换原则、依赖注入(倒转)原则、接口分离原则、迪米特原则、合成聚合复用原则。

原则一单一职责原则单一职责原则(SRP:Single responsibility principle)又称单一功能原则核心:解耦和增强内聚性(高内聚,低耦合)。

描述:类被修改的几率很大,因此应该专注于单一的功能。

如果你把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能,这时就需要新一轮的测试来避免可能出现的问题。

原则二里氏替换原则里氏替换原则(LSP:Liskov Substitution Principle)核心:在任何父类出现的地方都可以用他的子类来替代(子类应当可以替换父类并出现在父类能够出现的任何地方)四层含义:(1)子类必须完全实现父类的方法。

在类中调用其他类是务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。

(2)子类可以有自己的个性。

子类当然可以有自己的行为和外观了,也就是方法和属性(3)覆盖或实现父类的方法时输入参数可以被放大。

即子类可以重载父类的方法,但输入参数应比父类方法中的大,这样在子类代替父类的时候,调用的仍然是父类的方法。

即以子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松。

(4)覆盖或实现父类的方法时输出结果可以被缩小。

原则三依赖注入原则依赖注入原则(DIP:Dependence Inversion Principle)别名:依赖倒置原则或依赖反转原则核心:要依赖于抽象,不要依赖于具体的实现三层含义:(1)高层模块不应该依赖低层模块,两者都应该依赖其抽象(抽象类或接口);(2)抽象不应该依赖细节(具体实现);(3)细节(具体实现)应该依赖抽象。

uml试题及答案

uml试题及答案

【用例图】.用例图的节点包括1ABD)A、用例B、边界C、关联D、执行者.用例之间的关系主要有[BCD)A、聚合B、继承C、扩展D、包含.在承受用例模型捕获需求时,需要执行如下[ABCD)操作A、描述非功能需求B、用例建模C、识别用例D、识别参与者.在识别用例时,以下[ABC)问题可以帮助识别用例A、当系统状态发生故障时,是否需要通知参与者B、系统是否存在外部大事,假设存在,是哪个能参与者通知系统这些个部大事C、参与者期望系统为他供给什么样的功能D、系统运行环境是什么1.在用例图中,可以用⑴)来表示整个软件系统或其中一些子系统的边界,也可以用它表示软件系统的不同公布版本的功能范围A、执行者 B、关联关系 C、用例D、边界框6.山〕作为完成用例任务的责任担当者,协调、掌握其他类共同完成用例规定的功能或行为A、数据对象B、掌握类C、实体类D、边界类.基丁•用例图的需求捕获的第一步就是确定系统的参与者,在查找系统参与者时,可以依据以下(ABCD]等问题来确定A、系统同环境如何进展交互. (A)可以用于帮助设计人员在UML模型为模型定义约束信息,创立更为准确的设计模型A、OCLB、表达式C、属性D、变量. UML2. 0在1.0的根底上,对如下[ABCD)的建模力量进展了增加A、活动B、交互C、简单构造D、状态机7.在界面设计中,通常屏幕的⑴)表示与软件系统的运行状态无关、在任何状况下均没有变化的文本、图标[icon)、图形(graph)、图象(image)等A、用户命令元素B、用户输入元素C、动态元素D、静态元素8.在界面设计中,通常屏幕的〔C〕表示在屏幕上预留空位、由用户在界面操作中填写或选择的界面元素,包括可编辑的文本、单项选择钮(radio)、多项选择框(checkbox)、选择列表(select list) 等A、静态元素B、动态元素C、用户输入元素D、用户命令元素.对于一个学校的课程注册治理系统,假设有一条需求为“学生只能查看本人选课打算;教师只能查看本人所开课程的学生信息;教务治理员可以查看全部信息。

(五)合成聚合复用原则

(五)合成聚合复用原则

(五)合成聚合复⽤原则《java与模式》笔记(五) 合成/聚合复⽤原则☆合成/聚合复⽤原则经常⼜叫做合成复⽤原则。

该原则就是在⼀个新的对象⾥⾯使⽤⼀些已有的对象,使之成为新对象的⼀部分:新的对象通过向这些对象的委派达到复⽤已有功能的⽬的。

ξ 10.1 合成与聚合的区别合成和聚合均是关联的特殊情况。

聚合⽤来表⽰“拥有”关系或者整体与部分的关系;⽽合成则⽤来表⽰⼀种强得多的“拥有”关系。

在⼀个合成关系⾥⾯,部分和整体的⽣命周期是⼀样的。

⼀个合成的新的对象完全拥有对其组成部分的⽀配权,包括它们的创建和销毁等。

使⽤程序语⾔的术语来说,组合⽽成的新对象对组成部分的内存分配、内存释放有绝对的责任。

ξ 10.2 复⽤的基本种类☆合成/聚合复⽤①优点:新对象存取成分对象的唯⼀⽅法是通过成分对象的接⼝;这种复⽤是⿊箱复⽤,因为成分对象的内部细节是新对象所看不见的;这种复⽤⽀持包装;这种复⽤所需的依赖较少;每⼀个新的类可以将焦点集中在⼀个任务上;这种复⽤可以在运⾏时动态进⾏,新对象可以使⽤合成/聚合关系将新的责任委派到合适的对象。

②缺点:通过这种⽅式复⽤建造的系统会有较多的对象需要管理。

☆继承复⽤①优点:新的实现较为容易,因为基类的⼤部分功能可以通过继承关系⾃动进⼊派⽣类;修改或扩展继承⽽来的实现较为容易。

②缺点:继承复⽤破坏包装,因为继承将基类的实现细节暴露给派⽣类,这种复⽤也称为⽩箱复⽤;如果基类的实现发⽣改变,那么派⽣类的实现也不得不发⽣改变;从基类继承⽽来的实现是静态的,不可能在运⾏时发⽣改变,不够灵活。

ξ 10.3 对违反⾥⽒替换原则的另外⼀种重构⽅案下图左⾯的UML是违反⾥⽒替换原则的。

雇员、经理和学⽣从⼈派⽣,⽽实际上这三种派⽣类应该描述⼀种⾓⾊,⼀个⼈可能同时是经理和学⽣,也可能同时是雇员和经理,这个时候通过继承来实现复⽤显然是不合适的。

右图通过重构抽象出⾓⾊接⼝,雇员、经理和学⽣都是⾓⾊接⼝的实现,然后采⽤合成/聚合的⽅式进⾏复⽤:☆ Coad条件是判断是否使⽤继承复⽤的通俗描述,只有在所有条件满⾜时,才应该考虑使⽤继承,它的内容是:①派⽣类是基类的⼀个特殊种类,⽽不是基类的⼀个⾓⾊,即要分清"Has-A"和"Is-A"的区别;②永远不会出现需要将派⽣类换成另⼀个类的派⽣类的情况;③派⽣类具有扩展基类的责任,⽽不是具有置换或者注销掉基类的责任;④只有在分类学⾓度有意义时,才可以使⽤继承。

面向对象编程的五大原则

面向对象编程的五大原则

面向对象编程的五大原则单一职责原则开放封闭原则里氏替换原则依赖倒置原则接口隔离原则高层的实现不应该依赖底层,(父类可以替换掉任何子类),具体说就是我们要针对接口抽象来编程,不要针对实现来编程,这样程序才能解耦。

一、"开-闭"原则(Open-Closed Principle,OCP)1.1"开-闭"原则的定义及优点1)定义:一个软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification.)。

即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。

2)满足"开-闭"原则的系统的优点a)通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。

b)已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。

c)这样的系统同时满足了可复用性与可维护性。

1.2如何实现"开-闭"原则在面向对象设计中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。

换言之,定义一个一劳永逸的抽象设计层,允许尽可能多的行为在实现层被实现。

解决问题关键在于抽象化,抽象化是面向对象设计的第一个核心本质。

对一个事物抽象化,实质上是在概括归纳总结它的本质。

抽象让我们抓住最最重要的东西,从更高一层去思考。

这降低了思考的复杂度,我们不用同时考虑那么多的东西。

换言之,我们封装了事物的本质,看不到任何细节。

在面向对象编程中,通过抽象类及接口,规定了具体类的特征作为抽象层,相对稳定,不需更改,从而满足"对修改关闭";而从抽象类导出的具体类可以改变系统的行为,从而满足"对扩展开放"。

对实体进行扩展时,不必改动软件的源代码或者二进制代码。

【设计模式】第一篇:概述、耦合、UML、七大原则,详细分析总结(基于Java)

【设计模式】第一篇:概述、耦合、UML、七大原则,详细分析总结(基于Java)

【设计模式】第⼀篇:概述、耦合、UML、七⼤原则,详细分析总结(基于Java)迷茫了⼀周,⼀段时间重复的 CRUD ,着实让我有点烦闷,最近打算将这些技术栈系列的⽂章先暂时搁置⼀下,开启⼀个新的篇章《设计模式》,毕竟前⾯写了不少 “武功招式” 的⽂章,也该提升⼀下内功了⼀设计模式概述(⼀) 什么是设计模式设计模式,即Design Patterns,是指在软件设计中,被反复使⽤的⼀种代码设计经验。

使⽤设计模式的⽬的是为了可重⽤代码,提⾼代码的可扩展性和可维护性1995年,GoF(Gang of Four,四⼈组/四⼈帮)合作出版了《设计模式:可复⽤⾯向对象软件的基础》⼀书,收录了23种设计模式,从此树⽴了软件设计模式领域的⾥程碑,【GoF设计模式】(⼆) 为什么学习设计模式前⾯我们学习了 N 种不同的技术,但是归根结底,也只是 CRUD 与调⽤之间的堆砌,或许这个创意亦或是业务很完善、很强⼤,其中也巧妙运⽤了各种⾼效的算法,但是说⽩了,这也只是为了实现或者说解决某个问题⽽做的还有时候,两个⼈同时开发⼀款相同的产品,均满⾜了预期的需求,但是 A 的程序,不仅代码健壮性强,同时后期维护扩展更是便捷(这种感觉,我们会在后⾯具体的设计模式中愈发的感觉到)⽽ B 的代码却是⼀⾔难尽啊有⼀句话总结的⾮常好:设计模式的本质是⾯向对象设计原则的实际运⽤,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解也就是说,毕竟像例如Java这样⾯向对象的语⾔中,如何实现⼀个可维护,可维护的代码,那必然就是要降低代码耦合度,适当复⽤代码,⽽要实现这⼀切,就需要充分的利⽤ OOP 编程的特性和思想注:下⾯第⼆⼤点补充【耦合】的相关概念,若不需要跳转第三四⼤点【UML类图及类图间的关系】/【设计模式七⼤原则】在之前我写 Spring依赖注⼊的时候【万字长⽂】 Spring框架层层递进轻松⼊门(0C和D),就是从传统开发,讲到了如何通过⼯⼚模式,以及多例到单例的改进,来⼀步步实现解耦,有兴趣的朋友可以看⼀下哈⼆什么是耦合?(⾼/低)作为⼀篇新⼿都能看懂的⽂章,开始就⼀堆 IOC AOP等专业名词扔出去,好像是不太礼貌,我得把需要铺垫的知识给⼤家尽量说⼀说,如果对这块⽐较明⽩的⼤佬,直接略过就OK了耦合,就是模块间关联的程度,每个模块之间的联系越多,也就是其耦合性越强,那么独⽴性也就越差了,所以我们在软件设计中,应该尽量做到低耦合,⾼内聚⽣活中的例⼦:家⾥有⼀条串灯,上⾯有很多灯泡,如果灯坏了,你需要将整个灯带都换掉,这就是⾼耦合的表现,因为灯和灯带之间是紧密相连,不可分割的,但是如果灯泡可以随意拆卸,并不影响整个灯带,那么这就叫做低耦合代码中的例⼦:来看⼀个多态的调⽤,前提是 B 继承 A,引⽤了很多次A a = new B();a.method();如果你想要把B变成C,就需要修改所有new B()的地⽅为new C()这也就是⾼耦合如果如果使⽤我们今天要说的 spring框架就可以⼤⼤的降低耦合A a = BeanFactory().getBean(B名称);a.method();这个时候,我们只需要将B名称改为C,同时将配置⽂件中的B改为C就可以了常见的耦合有这些分类:(⼀) 内容耦合当⼀个模块直接修改或操作另⼀个模块的数据,或者直接转⼊另⼀个模块时,就发⽣了内容耦合。

设计模式(Design Patterns)可复用面向对象软件的基础

设计模式(Design Patterns)可复用面向对象软件的基础

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。

项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

本章系Java之美[从菜鸟到高手演变]系列之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师!一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。

用一个图片来整体描述一下:二、设计模式的六大原则1、开闭原则(Open Close Principle)开闭原则就是说对扩展开放,对修改关闭。

在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。

所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。

想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。

里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。

组合复用原则

组合复用原则

: void : TeacherDTO : List : int
合成聚合复用原则
来看个比较直观的例子:
实例说明
“韩信带兵,多多益善”,韩信之所以有很大的影响力,一方面归功他 建立了很大的功勋;另外一方面是因为他手握重兵。建立很大的功勋 甚至是功高盖主,这就直接导致韩信在军队中深得人心,毕竟,作为 士兵,很少有不愿意追随一个在战场上无往不胜的领袖的;手握重兵, 有合成聚合的原则来说就是对自己统领的士兵将士保持有引用,就是 聚合。韩信手中聚合有一大批能征善战的人,随时听从韩信的调遣. 而“普天之下,莫非王土;四海之内,莫非王臣”,韩信拥有士兵, 刘邦却拥有天下,何况韩信也并非拥有全部士兵。“君叫臣死,臣不 得不死”,刘邦拥有对天下苍生的生杀大权。韩信很清楚,“陛下虽 不善统兵,却善御将”。刘邦是拥有一种比韩信更强的“拥有”关系, 可以主宰生死,同时也可以主宰韩信的生死。这就相当于合成关系。 更重要的是韩信也是合成关系的一个成员,是刘邦的将领。
现使用合成复用原则对其进行重构。
合成聚合复用原则
合成复用原则实例
实例解析
NewDBUtil + getConnection () : Connection ...
DBUtil + getConnection () : Connection ...
StudentDAO - dBOperator : DBUtil + setDBOperator (DBUtil dBOperator) + findStudentById (String id) + findAllStudents () + save (StudentDTO student) ...
面向对象设计原则

七大设计原则

七大设计原则

七⼤设计原则⼀:单⼀职责原则(全称:“Single-Responsibility Principle”)⼜称单⼀功能原则核⼼:解耦和增强内聚性(⾼内聚,低耦合)说明:就⼀个类⽽⾔,应该只专注于做⼀件事和仅有⼀个引起它变化的原因。

所谓职责,我们可以理解他为功能,就是设计的这个类功能应该只有⼀个,⽽不是两个或更多。

也可以理解为引⽤变化的原因,当你发现有两个变化会要求我们修改这个类,那么你就要考虑撤分这个类了。

因为职责是变化的⼀个轴线,当需求变化时,该变化会反映类的职责的变化。

使⽤SRP注意点:1、⼀个合理的类,应该仅有⼀个引起它变化的原因,即单⼀职责;2、在没有变化征兆的情况下应⽤SRP或其他原则是不明智的;3、在需求实际发⽣变化时就应该应⽤SRP等原则来重构代码;4、使⽤测试驱动开发会迫使我们在设计出现臭味之前分离不合理代码;5、如果测试不能迫使职责分离,僵化性和脆弱性的臭味会变得很强烈,那就应该⽤Facade或Proxy模式对代码重构;SRP优点:消除耦合,减⼩因需求变化引起代码僵化。

⼆、依赖倒转原则(全称:“Dependence Inversion Principle”)⼜称依赖倒置原则或依赖反转原则核⼼:要依赖于抽象,不要依赖于具体的实现优点:使⽤传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。

依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。

怎样做到依赖倒置?以抽象⽅式耦合是依赖倒转原则的关键。

抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引⽤到基类的地⽅都可以改换成其⼦类,因此,⾥⽒代换原则是依赖倒转原则的基础。

在抽象层次上的耦合虽然有灵活性,但也带来了额外的复杂性,如果⼀个具体类发⽣变化的可能性⾮常⼩,那么抽象耦合能发挥的好处便⼗分有限,这时可以⽤具体耦合反⽽会更好。

层次化:所有结构良好的⾯向对象构架都具有清晰的层次定义,每个层次通过⼀个定义良好的、受控的接⼝向外提供⼀组内聚的服务。

面向对象设计的七大原则

面向对象设计的七大原则

⾯向对象设计的七⼤原则在上⼀篇⾥我们谈了谈为何设计模式,那接下来我们再浅谈⼀下在⾯向对象设计中我们常常要遵循的⼀些原则。

这些原则是经过⽆数的前⼈总结出来的经验的结晶。

仅仅有遵循这些原则。

你才有可能涉及出优秀的代码。

今天我们要谈的原则有七⼤原则,即:单⼀职责。

⾥⽒替换。

迪⽶特法则,依赖倒转,接⼝隔离,合成/聚合原则。

开放-封闭。

1. 开闭原则定义:软件实体应当对扩展开放,对改动关闭。

这句话说得有点专业。

更通俗⼀点讲,也就是:软件系统中包括的各种组件,⽐如模块(Modules)、类(Classes)以及功能(Functions)等等。

应该在不改动现有代码的基础上。

去扩展新功能。

开闭原则中“开”。

是指对于组件功能的扩展是开放的。

是同意对其进⾏功能扩展的。

开闭原则中“闭”。

是指对于原有代码的改动是封闭的,即不应该改动原有的代码。

问题由来:凡事的产⽣都有缘由。

我们来看看。

开闭原则的产⽣缘由。

在软件的⽣命周期内,由于变化、升级和维护等原因须要对软件原有代码进⾏改动时。

可能会给旧代码中引⼊错误,也可能会使我们不得不正确整个功能进⾏重构,⽽且须要原有代码经过⼜⼀次測试。

这就对我们的整个系统的影响特别⼤。

这也充分展现出了系统的耦合性假设太⾼,会⼤⼤的添加后期的扩展。

维护。

为了解决问题,故⼈们总结出了开闭原则。

解决开闭原则的根本事实上还是在解耦合。

所以。

我们⾯向对象的开发,我们最根本的任务就是解耦合。

解决⽅法:当软件须要变化时。

尽量通过扩展软件实体的⾏为来实现变化。

⽽不是通过改动已有的代码来实现变化。

⼩结:开闭原则具有理想主义的⾊彩。

说的⾮常抽象,它是⾯向对象设计的终极⽬标。

其它⼏条原则,则能够看做是开闭原则的实现。

我们要⽤抽象构建框架,⽤实现扩展细节。

2. 单⼀职责原则(Single Responsibility Principle)定义:⼀个类。

仅仅有⼀个引起它变化的原因。

即:应该仅仅有⼀个职责。

每个职责都是变化的⼀个轴线。

六大设计原则

六大设计原则

六⼤设计原则六⼤设计原则1. 单⼀职责原则:对于⼀个类,应该只有⼀个引起它变化的原因;【功能内聚】2. ⾥⽒代换原则:⼦类必须能够替换掉它们的⽗类型;【减⼩继承耦合】3. 开放-封闭原则:对于扩展是开放的;对于修改是封闭的。

4. 依赖倒置原则:程序的⾼层模块不应该依赖于底层模块,两者应依赖于抽象;抽象不应该依赖于具体斜街,⽽细节应该依赖于抽象。

【⾯向接⼝编程,⽽不是针对实现编程】【耦合具有⽅向性差异,稳定与变化之间的耦合,接⼝稳定⽽具体易变化】5. 合成/聚合复⽤原则:尽量不使⽤类继承,⽽尽量使⽤合成/聚合【避免类爆炸】6. 迪⽶特法则:如果两个类之间不必直接通信,则这个类不应该发⽣直接相互作⽤。

如果其中⼀个类需要调⽤另⼀个类的某个⽅法,可以通过第三⽅转发这个调⽤。

【体现在顺序图中,跨“朋友/友元”调⽤“陌⽣”对象,进⾏改进】⼀、单⼀职责原则举例:超⼈只维护世界原因:易于维护和⾼度的可复⽤性是⾯向对象开发的⽐较突出的两个优点。

若职责过于庞⼤,则维护困难,可复⽤性也随之降低,与⾯向对象的思想背道⽽驰。

好处:降低类的复杂度,⼀个类只负责⼀项职责,其逻辑肯定⽐负责多项职责简单;提⾼类的可读性,提⾼系统的可维护性。

⼆、⾥⽒代换原则举例:超⼈只维护世界符合:鲨鱼是鱼,⽼⽊匠徒弟替⽼⽊匠打家具;违反:正⽅形是长⽅形【如何修改,构造⼀个抽象的四边形类】作⽤:使得使⽤⽗类类型的模块在⽆需修改的情况下,就可以通过使⽤不同的⼦类拓展。

⾥⽒代换规则是对实现抽象化的具体步骤的规范。

【⾥⽒代换原则是对开闭原则的进⼀步规范】三、开放-封闭原则(OCP)----⾯向对象设计的主要⽬标原因:封装变化、降低耦合效果:开闭原则提供了⼀个使系统在⾯对需求变更时,可以保持系统相对稳定的解决⽅案。

举例:符合:动物-猫-咪咪(继承/多态复⽤,并拓展)对⽐:1. 银⾏业务员(存款、取款、转账、进⾏基⾦申购)2. 银⾏业务员接⼝,存款业务员、取款业务员、负责转账业务员、基⾦业务员//其实这⾥的改写也体现了单⼀职责原则,依赖于抽象的银⾏业务员接⼝利于扩展核⼼思想:只依赖于抽象,⾯向抽象编程,⽽不是⾯向具体编程。

合成复用原则举例c++__概述说明以及解释

合成复用原则举例c++__概述说明以及解释

合成复用原则举例c++ 概述说明以及解释1. 引言1.1 概述在软件开发中,重用已有的代码是一个重要的话题。

合成复用原则是一种设计原则,它强调通过组合已有对象或模块来实现新功能而不是通过继承已有类来达到代码复用的目的。

本文将介绍合成复用原则在C++语言中的应用,并提供相关示例和解释。

1.2 文章结构本文分为四个部分:引言、合成复用原则、C++的合成复用原则实例以及结论。

在引言中,我们将简要介绍文章背景和目标,并提供整体文章结构。

接下来,我们将详细讲解合成复用原则的定义、背景和原则解释。

然后,我们将以C++语言为例,展示如何实际应用该原则,并分析示例代码。

最后,在结论部分,我们将总结文章主要观点并提供进一步讨论。

1.3 目的本文旨在向读者介绍并解释合成复用原则在C++中的实际应用。

通过阐述该原则的定义、背景和解释,读者可以更好地理解这一设计原则,并学会如何利用该原则编写可重用、可扩展和易于维护的代码。

此外,通过具体的示例,读者将了解到合成复用原则的优势和注意事项。

最终,读者将能够更好地运用这一原则来提高软件开发效率和代码质量。

2. 合成复用原则:2.1 定义和背景:合成复用原则是软件工程中的一项设计原则,它通过将现有的类或模块组合或聚合起来创建新的功能,从而实现代码的复用。

该原则强调了将对象的组合与继承相比更具优势,并提倡使用组合关系而不是继承关系来实现代码的重用。

在软件开发中,复用是提高效率和减少冗余代码量的关键。

通过合理地利用已经存在的类、模块或方法,我们可以避免重新编写相同或类似功能的代码,节省开发时间和资源。

这种基于复用思想构建软件系统的方法被称为复用导向设计。

2.2 原则解释:合成复用原则强调了在设计过程中要优先选择组合而不是继承。

它鼓励通过将现有类作为新类的成员来构建系统,而不是通过继承已有类来获得功能。

继承虽然能够使代码重用,但当子类与父类之间存在紧耦合关系时会带来一些问题。

当父类发生变化时,子类也需要随之改变,这破坏了系统的灵活性和可维护性。

合成聚合复用原则

合成聚合复用原则

合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)合成(Composition)和聚合(Aggregation)都是关联(Association)的特殊种类。

聚合表示整体和部分的关系,表示“拥有”。

如奔驰S360汽车,对奔驰S360引擎、奔驰S360轮胎的关系是聚合关系,离开了奔驰S360汽车,引擎、轮胎就失去了存在的意义。

在设计中,聚合不应该频繁出现,这样会增大设计的耦合度。

合成则是一种更强的“拥有”,部分和整体的生命周期一样。

合成的新的对象完全支配其组成部分,包括它们的创建和湮灭等。

一个合成关系的成分对象是不能与另一个合成关系共享的。

换句话说,合成是值的聚合(Aggregation by Value),而一般说的聚合是引用的聚合(Aggregation by Reference)。

在面向对象设计中,有两种基本的办法可以实现复用:第一种是通过合成/聚合,即合成复用原则,含义是指,尽量使用合成/聚合,而不是使用继承。

第二种就是通过继承。

要正确地选择合成/复用和继承的方法是,只有当以下的条件全部被满足时,才应当使用继承关系:1)子类是父类的一个特殊种类,而不是父类的一个角色,也就是区分"Has-A"和"Is-A"。

只有"Is-A"关系才符合继承关系,"Has-A"关系应当用聚合来描述。

2)永远不会出现需要将子类换成另外一个类的子类的情况。

如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。

3)子类具有扩展父类的责任,而不是具有置换掉(override)或注销掉(Nullify)父类的责任。

如果一个子类需要大量的置换掉父类的行为,那么这个类就不应该是这个父类的子类。

4)只有在分类学角度上有意义时,才可以使用继承。

如果语义上存在着明确的is-a关系,并且这种关系是稳定的、不变的,则考虑使用继承;如果没有is-a关系,或者这种关系是可变的,使用合成。

合成(组合)聚合复用原则

合成(组合)聚合复用原则

合成(组合)聚合复⽤原则1.定义:尽量使⽤对象组合/聚合,⽽不是继承关系达到软件复⽤的⽬的2.聚合has-A和组合contains-A3.优点:可以使系统更加灵活,降低类与类之间的耦合度,⼀个类的变化对其他类造成的影响相对较少4.思考:何时使⽤合成/聚合、继承?聚合has-A、组合contains-A、继承is-A5.实例⽬录package6.实例UML类图7.代码1package positionaggregation;23public abstract class DBConnection {4/*public String getConnection(){5 return "MySQL数据库连接";6 }*/7public abstract String getConnection();8 }1package positionaggregation;23public class MySQLConnection extends DBConnection{4public String getConnection() {5return "MySQL数据库连接";6 }7 }1package positionaggregation;23public class PostgreSQLConnection extends DBConnection {4public String getConnection() {5return "PostgreSQL数据库连接";6 }7 }1package positionaggregation;23public class ProductDao{// extends DBConnection4private DBConnection dbConnection;56public void setDbConnection(DBConnection dbConnection) {7this.dbConnection = dbConnection;8 }910public void addProduct(){11 String conn = dbConnection.getConnection();12 System.out.println("使⽤"+conn + "增加产品");13 }14 }1package positionaggregation;23public class Test {4public static void main(String[] args) {5 ProductDao productDao = new ProductDao();6 productDao.setDbConnection(new MySQLConnection());7 productDao.addProduct();8 productDao.setDbConnection(new PostgreSQLConnection());9 productDao.addProduct();10 }11 }。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在对违反里氏代换原则的设计进行重 构时,有两种方法: 一是加入一个抽象超类; 二是将继承改为合成/聚合的关系。
里氏代换原则(LSP)
一个软件实体如果适用于一个基类的 话,那么一定适用于其子类,而且它根本 不能察觉出基类对象和子类对象的区别。
区分“Is-A”和 “Has-A”
Is-A”代表一个类是另外一个类的一种 “Has-A”代表一个类是另一个类的一个角 色,而不是另一个类的特殊种类。 对于"Is-A"应该考虑使用继承,而 "Has-A"使用合成/聚合。
合成和聚合均是关联的特殊种类。 聚合:“拥有”关系或整体与部分的关系; 是引用的聚合 合成:一种强得多的“拥有”关系; 是值的聚合
关于合成关系
其部分和整体的生命周期是一样的。 一个合成的新对象完全拥有对其组成成分 的支配权,包括它们的创建和销毁等。 更进一步讲,一个合成关系中的成员 对象是不能与另一个合成对象共享的。如 果一个合成关系销毁了,那么所有的成员 对象要么自己销毁所有的成员对象(较普 遍),要么就得将这一责任交给别的对象 (较罕见)。
合成/聚合复用主要缺点
通过这种复用建造的系统会有较多的对 象需要管理。
通过继承达到复用的目的
合成/聚合作为复用手段可以应用到 几乎任何环境中去,而继承只能在有限的 环境中使用。尽管继承是一种非常重要的 复用手段,但应当首先考虑合成/聚合,而 / 不是继承。
继承复用优点:
新的实现较为容易,因为超类的大部分功 能可以通过继承的关系自动进入子类。 修改和扩展继承而来的实现较为容易。
Java.util. Properties
一个性质列( Properties )不是一个 Hashtable。此时,使用聚合比使用继承 关系更为合适。 我们可以看一下如下情况:
不恰当处
1.由于Properties继承了Hashtable行为,因而 当p是一个Properties类型的对象时, p.getProperties(key)与p.get(key)就会给出 不同的结果。 2.客户端可以通过类型的转换,直接使用超类型 的行为。 3.客户端可以通过Hashtable提供的行为加入任 意类型的键和值。绕过Properties接口,并导致 Properties的内部矛盾和崩溃。
复用的基本种类
在面向对象的设计里,有两种基本的 方法可以在不同的环境中复用已有的设计 和实现,即通过合成/聚合或继承。 那么此两种方法在可维护性上面有何 区别呢?
合成/聚合复用
好处
新对象存取成分对象的唯一方法是通过成分对象 的接口。 这种复用是黑箱复用,因为成分对象的内部细节 是新对象所看不见的。 这种复用支持包装。 这种复用所需的依赖较少。 这种复用可以在运行时间内动态进行,新对象可 以动态的引用与成分对象类型相同的对象。
面向对象设计方法
L07 B 合成/聚合复用原则(CAPP) wxz
概要
合成、聚合复用原则就是在一个新的 对象里面使用一些已有的对象,使之成为 新对象的一部份,新的对象通过向这些对 象的委派达到复用已有功能的目的。 这个原则有一个简短的描述:要尽量 使用合成、聚合,尽量不要使用继承。
合成、聚合的区别
一个类是另一个类的一个角色
人 角色
雇员
经理
学生
与里氏代换原则联合使用
里氏代换原则是继承复用的基石。只有当 衍生类可以替换掉基类,软件单位的功能不会受 到影响时,基类才真正被复用,而衍生类也才能 够在基类的基础上增加新的功能。 如果两个类的关系是“Has-A”而不是“IsA”关系,这两个类一定违反里氏代换原则。 只有两个类满足里氏代换原则,才有可能 是“Is-A”关系。
继承复用缺点
继承复用破坏包装,因为继承将超类的实现细节 暴露给子类。由于超类的内部细节常常是对于子 类透明的,所以这种复用是透明的复用,又称 “白箱”复用。 如果超类发生改变,那么子类的实现也不得不发 生改变。 从超类继承而来的实现是静态的,不可能在运行 时间内发生改变,没有足够的灵活性。
从代码重构的角度理解
Java语言API中的例子
在Java语言的API中,有几个明显违 反这一原则的例子,其中最著名的就是 Stack和Properties。 在此,以后者为例阐述: Properties被不恰当的设置成 Hashtable子类,如下图所示:
Dictionary Map Colneable Java.io.Serializable Java.util. Hashtable
相关文档
最新文档