7 设计模式原则之合成复用原则

embedded/2024/11/22 11:14:58/

一、什么是合成复用原则

1.定义:

要尽量使用对象组合(组合关系)来实现代码复用,而不是通过类继承(继承关系)来实现。

2.继承 vs. 组合

  • 继承是一种“强耦合”的关系,子类会受父类的影响(例如当父类修改时,子类可能需要跟着修改)。
  • 组合则是一种“弱耦合”的关系,通过在类中包含其他对象来实现功能的扩展。

3.合成复用原则的优点

  1. 降低耦合性:组合关系让类之间的依赖变得更加松散。
  2. 提高灵活性:组合比继承更容易应对需求变化。
  3. 增强可维护性:修改或扩展功能时,可以针对组合对象进行调整,而不必修改现有类。

二、为什么需要合成复用原则

在使用继承的过程中,虽然能快速实现代码复用,但也会带来以下问题:

  1. 继承违背了封装性:子类直接依赖于父类的实现细节,父类的任何变化都会影响子类。
  2. 继承缺乏灵活性:继承是一种“静态”的关系,一旦继承关系确定,就无法动态更改父类的功能。
  3. 可能造成类爆炸:当继承层级过深时,会导致系统变得复杂,难以维护。

通过使用对象组合,可以动态地组合对象的行为,避免继承带来的问题,从而更灵活地实现代码复用。

三、代码举例

1.使用继承实现代码复用

以下代码展示了使用继承实现代码复用的情况:

java">// 基础车辆类
public class Vehicle {public void move() {System.out.println("Vehicle is moving");}
}// 汽车类
public class Car extends Vehicle {public void startEngine() {System.out.println("Car engine started");}
}// 飞机类
public class Airplane extends Vehicle {public void fly() {System.out.println("Airplane is flying");}
}// 客户端代码
public class Client {public static void main(String[] args) {Car car = new Car();car.move();car.startEngine();Airplane airplane = new Airplane();airplane.move();airplane.fly();}
}

2.问题分析

  • 过度依赖继承CarAirplane 都继承了 Vehicle 类。虽然它们可以共享 move() 方法,但继承使它们和 Vehicle 紧耦合。
  • 缺乏灵活性:如果 Vehicle 类中新增了其他方法(比如 sail()),可能会导致 CarAirplane 类也继承了不需要的功能。
  • 扩展困难:当我们需要为某些特殊车辆添加功能时,可能需要再创建更多的子类,造成类爆炸。

3.应用合成复用原则的例子

使用组合重构代码,将车辆的通用功能封装到独立的类中。

java">// 通用的移动功能
public class Moveable {public void move() {System.out.println("Moving...");}
}// 通用的飞行功能
public class Flyable {public void fly() {System.out.println("Flying...");}
}// 通用的引擎功能
public class Engine {public void start() {System.out.println("Engine started");}
}// 汽车类,使用组合实现功能
public class Car {private Moveable moveable;private Engine engine;public Car() {this.moveable = new Moveable();this.engine = new Engine();}public void move() {moveable.move();}public void startEngine() {engine.start();}
}// 飞机类,使用组合实现功能
public class Airplane {private Moveable moveable;private Flyable flyable;public Airplane() {this.moveable = new Moveable();this.flyable = new Flyable();}public void move() {moveable.move();}public void fly() {flyable.fly();}
}// 客户端代码
public class Client {public static void main(String[] args) {Car car = new Car();car.startEngine();car.move();Airplane airplane = new Airplane();airplane.move();airplane.fly();}
}

4.改进分析

  • 弱耦合CarAirplane 通过组合的方式使用 MoveableFlyableEngine 对象,它们之间的关系松散,修改任何一个类不会影响其他类。
  • 高内聚:每个类职责明确。Moveable 专注于移动,Flyable 专注于飞行,Engine 专注于引擎启动,符合单一职责原则。
  • 灵活性增强:我们可以轻松组合不同的功能。比如,为船只创建一个类时,只需组合 Moveable 和其他功能类即可,无需修改现有类。

四、总结

        合成复用原则是一种提高代码复用性和灵活性的重要设计原则。通过优先使用组合而非继承,可以让代码更易于扩展和维护。

原则对比
继承组合
强耦合,子类依赖于父类弱耦合,类之间通过组合实现
不灵活,父类变动会影响子类灵活,可动态更换组合关系
适用于“是一个”的关系适用于“有一个”的关系
设计建议
  • 如果对象之间的关系是“有一个”,优先使用组合。
  • 继承仅在表示“是一个”的强关联关系时使用,并避免继承层次过深。
  • 使用组合能让代码更符合开闭原则,易于扩展。

通过合理地使用合成复用原则,可以让你的代码更加优雅,具有更高的复用性和灵活性。

五、应用

在实际项目中,识别是否需要使用合成复用原则,可以问自己以下问题:

  1. 是否需要复用多个功能? 如果是,考虑组合。
  2. 功能是否会独立变化? 如果是,应该将其分离到独立的类中。
  3. 是否存在不必要的继承关系? 如果是,重构为组合关系。

赶紧尝试在你的项目中应用合成复用原则吧!让代码更加优雅、高效!


http://www.ppmy.cn/embedded/139608.html

相关文章

2024年亚太数学建模竞赛问题C宠物产业及相关产业发展分析与对策

随着人们消费理念的发展,随着经济的快速发展和人均收入的提高,宠物产业作为一个新兴产业在全球范围内逐渐积聚势头。1992年,中国小动物保护协会成立,随后1993年,皇家狗狗、玛氏等国际宠物品牌进入中国市场。随着“宠物…

【论文速读】| RobustKV:通过键值对驱逐防御大语言模型免受越狱攻击

基本信息 原文标题:ROBUSTKV: DEFENDING LARGE LANGUAGE MODELS AGAINST JAILBREAK ATTACKS VIA KV EVICTION 原文作者:Tanqiu Jiang, Zian Wang, Jiacheng Liang, Changjiang Li, Yuhui Wang, Ting Wang 作者单位:Stony Brook University…

极简AI工具箱网站开源啦!

开源地址:https://gitee.com/toolsj-open/go 反正也经营不下去了,一点流量都没有。虽然谈不上精品,但是我也用心做了。开源出来供学习吧,下面是详细文档: 相关仓库 mysql表结构:https://gitee.com/tools…

springboot基于协同过滤算法的的儿童图书推荐系统

摘 要 儿童图书推荐系统是一种基于计算机技术和信息管理的系统,旨在帮助儿童图书爱好者。该系统通过整合儿童图书、热销图书等数据,提供全面的儿童图书管理服务。 本文拟采用java技术和springboot搭建系统框架,后台使用MySQL数据库进行信息管…

加密市场动态:暴涨后的调整与未来趋势

1. 加密市场暴涨后进入调整,IV指标处于低位 经历了连续一周的暴涨后,加密市场开始显现疲态。据Greeks.live的宏观研究员Adam分析,比特币价格接近90000美元的关键点位,成为市场争夺的焦点。然而,近期特斯拉、英伟达等美…

【YOLOv8】安卓端部署-1-项目介绍

【YOLOv8】安卓端部署-1-项目介绍 1 什么是YOLOv81.1 YOLOv8 的主要特性1.2 YOLOv8分割模型1.2.1 YOLACT实例分割算法之计算掩码1.2.1.1 YOLACT 的掩码原型与最终的掩码的关系1.2.1.2 插值时的目标检测中提取的物体特征1.2.1.3 coefficients(系数)作用1.…

spring boot jpa中 Hibernate 注解 @Immutable 的使用场景

入门示例 使用 spring boot jpa 来操作数据库的增删改查是非常方便的,定义完 model 之后,直接定义JPA 即可,后续操作就很丝滑了: Table(name "host_spec_price") Data Entity public class BudgetHost {IdGeneratedV…

zynq调试还是的用SystemDebuger不要用GDB

SystemDebugger可以看到更深的调用堆栈, 而GDB则只能看一部分的调用堆栈. 这将会是一个致命的问题.