面向对象设计原则之合成复用原则

合成复用原则又称为组合/聚合复用原则(Composition/Aggregate Reuse Principle, CARP),其定义如下:


合成复用原则(Composite Reuse Principle, CRP):尽量使用对象组合,而不是继承来达到复用的目的。

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承

在面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或通过继承,但首先应该考虑使用组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。


扩展

对于继承的深入理解,大家可以参考《软件架构设计》一书作者温昱先生的文章——《见山只是山见水只是水——提升对继承的认识》。

由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

一般而言,如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。"Is-A"是严格的分类学意义上的定义,意思是一个类是另一个类的"一种";而"Has-A"则不同,它表示某一个角色具有某一项责任。

下面通过一个简单实例来加深对合成复用原则的理解:


Sunny软件公司开发人员在初期的CRM系统设计中,考虑到客户数量不多,系统采用MySQL作为数据库,与数据库操作有关的类如CustomerDAO类等都需要连接数据库,连接数据库的方法getConnection()封装在DBUtil类中,由于需要重用DBUtil类的getConnection()方法,设计人员将CustomerDAO作为DBUtil类的子类,初始设计方案结构如图1所示:

图1  初始设计方案结构图

随着客户数量的增加,系统决定升级为Oracle数据库,因此需要增加一个新的OracleDBUtil类来连接Oracle数据库,由于在初始设计方案中CustomerDAO和DBUtil之间是继承关系,因此在更换数据库连接方式时需要修改CustomerDAO类的源代码,将CustomerDAO作为OracleDBUtil的子类,这将违反开闭原则。【当然也可以修改DBUtil类的源代码,同样会违反开闭原则。】

现使用合成复用原则对其进行重构。

根据合成复用原则,我们在实现复用时应该多用关联,少用继承。因此在本实例中我们可以使用关联复用来取代继承复用,重构后的结构如图2所示:

图2  重构后的结构图

在图2中,CustomerDAO和DBUtil之间的关系由继承关系变为关联关系,采用依赖注入的方式将DBUtil对象注入到CustomerDAO中,可以使用构造注入,也可以使用Setter注入。如果需要对DBUtil的功能进行扩展,可以通过其子类来实现,如通过子类OracleDBUtil来连接Oracle数据库。由于CustomerDAO针对DBUtil编程,根据里氏代换原则,DBUtil子类的对象可以覆盖DBUtil对象,只需在CustomerDAO中注入子类对象即可使用子类所扩展的方法。例如在CustomerDAO中注入OracleDBUtil对象,即可实现Oracle数据库连接,原有代码无须进行修改,而且还可以很灵活地增加新的数据库连接方式。

时间: 2024-09-29 00:53:41

面向对象设计原则之合成复用原则的相关文章

设计模式的七大原则(7) --合成复用原则

前言 我们终于学习最后一个设计原则了,其实博主更新的还是挺慢的,因为我想一个一个吃透以后再继续学习,切记不要囫囵吞枣. 基本介绍 其实这个能说的内容很少,就是:尽量使用合成/聚合的方式,而不是使用继承 为什么要这样做?有一下两点原因: 通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称"白箱"复用,如果基类发生改变,那么子类的实现也不得不发生改变:从基类继承而来的实现是静态的,不可

面向对象设计(OOD)七大原则

这篇文章我会不停的维护它,它将会越来越长,但它是关于我在面向对象中的一些学习的思考心得.希望对自己对各位都能实用处. 开篇前,说明一下写这篇文章的原因.原因是由于设计模式.由于设计模式里的各种模式.都是建立在这些原则之上的. 好比盖房子须要夯实的地基,或者比作数学论证中的使用到的公理.你不能说为什么盖房子一定要建立在地基之上.也不能说为什么两点一直线,三点一面这些公理为什么就这么牛逼的存在,由于这是自然规律.你必须遵守它们. 这些设计原则也类似,它们没有24种设计模式那样华丽的身姿,但它们是程序

融会贯通——最常用的“合成复用原则”技能点Get

复用一个类的时候,多使用对象的组合/聚合的关联关系,而不是继承. 之前提到的"依赖倒转原则",是以里氏代换原则为基础的实现开闭原则目标的手段,这一条路线涉及到的是类的继承(包括单继承和接口实现),他们支撑了Java多态的特性. 但是今天要谈一谈Java另一个特性--封装.封装就是不要暴露过多的基类内部细节给子类,让高层的操作神秘起来,不让小兵知道.合成复用原则体现的就是封装的特性. 所以可以推论出,多使用对象的组合/聚合关系,而不是继承,从而实现不会暴露过多的基类操作细节给子类的目的.

小菜学设计模式——合成复用原则

背景 本文标题为什么叫小菜学习设计模式,原因是本文内容主要是学习<大话设计模式>时的笔记摘要部分,当然,并不是记录书中小菜的学习过程,这个完全没有意义,而是指本人学习设计模式的成长之旅. 真诚的希望自己能够从一名小菜成长为一名大鸟! 编写的程序应该满足: 1)可维护 2)可扩展 3)可复用 4)够灵活 废话少说,言归正传,设计模式原则之:合成复用原则 书面理解 合成复用原则:要尽量使用合成/聚合,尽量不要使用继承. 对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现.子类

S.O.L.I.D: PHP 面向对象设计的五个基准原则

S.O.L.I.D 是首个 5 个面向对象设计 (OOD) 准则的首字母缩写,这些准则是由 Robert C. Martin 提出的,他更为人所熟知的名字是 Uncle Bob. 这些准则使得开发出易扩展.可维护的软件变得更容易.也使得代码更精简.易于重构.同样也是敏捷开发和自适应软件开发的一部分. S.O.L.I.D 意思是: 扩展出来的首字母缩略词看起来可能很复杂,实际上它们很容易理解. S - 单一功能原则 O - 开闭原则 L - 里氏替换原则 I - 接口隔离原则 D - 依赖反转原则

【OOAD】面向对象设计原则概述

软件的可维护性和可复用性 知名软件大师Robert C.Martin认为一个可维护性(Maintainability) 较低的软件设计,通常由于如下4个原因造成:? 过于僵硬(Rigidity) ? 过于脆弱(Fragility) ? 复用率低(Immobility) ? 黏度过高(Viscosity) 软件工程和建模大师Peter Coad认为,一个好的系统设计应该具备如下三个性质:? 可扩展性(Extensibility) ? 灵活性(Flexibility)? 可插入性(Pluggabil

面向对象设计原则之六:组合/聚集复用原则

组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP).组合和聚合都是对象建模中关联(Association)关系的一种.聚合表示整体与部分的关系,表示"含有",整体由部分组合而成,部分可以脱离整体作为一个独立的个体存在.组合则是一种更强的聚合,部分组成整体,而且不可分割,部分不能脱离整体而单独存在.在合成关系中,部分和整体的生命周期一样,组合的新的对象完全支配其组成部分,包括他们的创建和销毁.一个合成关系中成分对象是不能与另外一个合成关

设计模式2 面向对象设计原则

面向对象设计原则  原则的目的 面向对象设计原创表  单一职责原则案例 开闭原则 案例 依赖倒转原则 案例 面向对象设计原则  对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一.在面向对象设计中,可维护性的复用是以设计原则为基础的.每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平.  面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含

面向对象设计的七大原则

在上一篇里我们谈了谈为何设计模式,那接下来我们再浅谈一下在面向对象设计中我们常常要遵循的一些原则. 这些原则是经过无数的前人总结出来的经验的结晶. 仅仅有遵循这些原则.你才有可能涉及出优秀的代码.今天我们要谈的原则有七大原则,即:单一职责.里氏替换.迪米特法则,依赖倒转,接口隔离,合成/聚合原则.开放-封闭 . 1.   开闭原则 定义:软件实体应当对扩展开放,对改动关闭.这句话说得有点专业.更通俗一点讲,也就是:软件系统中包括的各种组件,比如模块(Modules).类(Classes)以及功能