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

发布时间 - 2026-01-11 02:40:33    点击率:

合成聚合复用原则

合成复用原则又称为组合/聚合复用原则(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  # 合成复用  # 聚合复用  # java利用Future实现多线程执行与结果聚合实例代码  # Java Fluent Mybatis 聚合查询与apply方法详解流程篇  # Java依赖-关联-聚合-组合之间区别_动力节点Java学院整理  # Flink实现特定统计的归约聚合reduce操作  # 复用  # 子类  # 可以使用  # 结构图  # 已有  # 重构  # 可以通过  # 关联关系  # 如图  # 所示  # 使之  # 源代码  # 少用  # 象中  # 是一个  # 连接数据库  # 开闭  # 还可以  # 两种  # 而来 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: javascript中闭包概念与用法深入理解  Laravel集合Collection怎么用_Laravel集合常用函数详解  如何撰写建站申请书?关键要点有哪些?  音乐网站服务器如何优化API响应速度?  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法  Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  北京网站制作公司哪家好一点,北京租房网站有哪些?  Mybatis 中的insertOrUpdate操作  Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】  Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】  如何在万网开始建站?分步指南解析  PHP 500报错的快速解决方法  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  UC浏览器如何设置启动页 UC浏览器启动页设置方法  香港服务器选型指南:免备案配置与高效建站方案解析  Android中AutoCompleteTextView自动提示  智能起名网站制作软件有哪些,制作logo的软件?  如何在万网自助建站平台快速创建网站?  Swift中swift中的switch 语句  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  如何用花生壳三步快速搭建专属网站?  Android使用GridView实现日历的简单功能  再谈Python中的字符串与字符编码(推荐)  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能  Laravel如何连接多个数据库_Laravel多数据库连接配置与切换教程  网站制作企业,网站的banner和导航栏是指什么?  香港服务器租用费用高吗?如何避免常见误区?  高防服务器如何保障网站安全无虞?  php做exe能调用系统命令吗_执行cmd指令实现方式【详解】  中国移动官方网站首页入口 中国移动官网网页登录  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  Laravel定时任务怎么设置_Laravel Crontab调度器配置  如何批量查询域名的建站时间记录?  如何在云主机上快速搭建多站点网站?  如何基于云服务器快速搭建网站及云盘系统?  教学论文网站制作软件有哪些,写论文用什么软件 ?  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  如何在建站之星绑定自定义域名?  Laravel如何使用Collections进行数据处理?(实用方法示例)  Laravel如何实现API版本控制_Laravel版本化API设计方案  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?  Windows Hello人脸识别突然无法使用  Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程