合成聚合复用原则_动力节点Java学院整理

 更新时间:2017年08月07日 10:15:52   作者:lovelion  
这篇文章主要介绍了合成聚合复用原则,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

合成聚合复用原则

合成复用原则又称为组合/聚合复用原则(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数据库连接,原有代码无须进行修改,而且还可以很灵活地增加新的数据库连接方式。

相关文章

  • Java实现TFIDF算法代码分享

    Java实现TFIDF算法代码分享

    这篇文章主要介绍了Java实现TFIDF算法代码分享,对算法进行了简单介绍,概念,原理,以及实现代码的分享,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • 借助Maven搭建Hadoop开发环境的最详细教程分享

    借助Maven搭建Hadoop开发环境的最详细教程分享

    在Maven插件的帮助下,VSCode写Java其实非常方便,所以本文就来和大家详细讲讲如何借助maven用VScode搭建Hadoop开发环境,需要的可以参考下
    2023-05-05
  • Sentinel初始化启动流程详细介绍

    Sentinel初始化启动流程详细介绍

    Sentinel是一个分布式系统的流量控制组件,它可以实现限流与流控及降级等功能,提高系统的稳定性和可靠性,这篇文章主要介绍了Sentinel的初始化流程,感兴趣想要详细了解可以参考下文
    2023-05-05
  • iBatis习惯用的16条SQL语句

    iBatis习惯用的16条SQL语句

    iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快.这篇文章主要介绍了iBatis习惯用的16条SQL语句的相关资料,需要的朋友可以参考下
    2016-10-10
  • Spring Security OAuth2 实现登录互踢的示例代码

    Spring Security OAuth2 实现登录互踢的示例代码

    这篇文章主要介绍了Spring Security OAuth2实现登录互踢的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Java使用ByteBuffer进行多文件合并和拆分的代码实现

    Java使用ByteBuffer进行多文件合并和拆分的代码实现

    因为验证证书的需要,需要把证书文件和公钥给到客户,考虑到多个文件交互的不便性,所以决定将2个文件合并成一个文件交互给客户,但是由于是加密文件,采用字符串形式合并后,拆分后文件不可用,本文给大家介绍了Java使用ByteBuffer进行多文件合并和拆分,需要的朋友可以参考下
    2024-09-09
  • Java 控制流程、大数值、数组

    Java 控制流程、大数值、数组

    这篇文章主要给大家介绍的是Java 控制流程、大数值、数组的一些相关自来哦,感兴趣的小伙伴可以参考下面文章的具体内容,希望文章对你有所帮助
    2021-10-10
  • Java实现动态数字时钟

    Java实现动态数字时钟

    这篇文章主要为大家详细介绍了Java实现动态数字时钟,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • Springcloud seata nacos环境搭建过程图解

    Springcloud seata nacos环境搭建过程图解

    这篇文章主要介绍了Springcloud seata nacos环境搭建过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java基于外观模式实现美食天下食谱功能实例详解

    Java基于外观模式实现美食天下食谱功能实例详解

    这篇文章主要介绍了Java基于外观模式实现美食天下食谱功能,较为详细的讲述了外观模式的概念、原理并结合实例形似详细分析了Java基于外观模式实现美食天下食谱功能的具体操作步骤与相关注意事项,需要的朋友可以参考下
    2018-05-05

最新评论