【未来编程:AI如何通过合成复用原则优化设计】
【未来编程:AI如何通过合成复用原则优化设计】
前言本文主要讲解合成复用原则为什么能替代继承复用原则。合成复用原则含义 合成复用原则(Composition over Inheritance)是一种设计思想,强调通过对象组合(合成)来实现复用,而不是通过继承。它的核心思想是,创建灵活的对象,并通过组合而不是继承来增强功能,避免了继承层次过深和过于紧耦合的问题。尽量先使用组合或者聚合等关联关系来实现
【未来编程:AI如何通过合成复用原则优化设计】
- 本文主要讲解
合成复用原则为什么能替代继承复用原则
。
含义
-
合成复用原则(Composition over Inheritance)
是一种设计思想,强调通过对象组合(合成)来实现复用,而不是通过继承。它的核心思想是,创建灵活的对象,并通过组合而不是继承来增强功能,避免了继承层次过深和过于紧耦合的问题。尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。 - 下面我们以鸭子实现飞和游泳行为来说明继承复用和组合复用的优缺点。
含义
继承复用(Inheritance Reuse)
是通过继承父类来复用父类的功能和行为。
UML图
- 我们知道在现实生活中,鸟会飞,鱼会游泳,鸭子不仅会飞也会游泳,但是在Java中如果要让鸭子实现这些行为,如果单靠继承是不可能的,因为Java只能单继承,一个类只能继承另一个类,如下类图中,如果鸭子要实现鸟飞的方式就要继承鸟类,但如果他还要实现游这个行为就需要调用游的接口去重写游泳的方法来实现。
实现代码
- 行为的实现接口
package principlesposition_Reuse.before;
public interface Flyable {
void fly();
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.before;
public interface Swmmable {
void swim();
}
- 实现的类
package principlesposition_Reuse.before;
public class Fish {
public void swim(){
println("鱼在游");
}
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.before;
public class Bird implements Flyable{
@Override
public void fly() {
println("鸟在咻咻飞");
}
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.before;
public class Duck extends Bird implements Swmmable{
@Override
public void swim() {
println("鸭鸭在游泳");
}
//继承飞
@Override
public void fly() {
println("鸭鸭噗噗的飞啦");
super.fly();//调用鸟的飞法
}
}
- 测试代码
package principlesposition_Reuse.before;
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.fly();
duck.swim();
}
}
运行结果及分析
- 根据运行结果及代码可以知道,我们的鸭鸭实现了游泳和飞的行为,因为它的飞是继承自鸟的,当我们用
super.fly()
去调用s时能够展示继承并复用父类的行为。它能够让我们看到父类的实现仍然可以在子类中被调用,并且我们还能在重写方法里面对父类的行为进拓展,也就是说鸭鸭不仅可以噗噗的飞也可以像鸟一样咻咻的飞,如上运行结果所示那样。 - 如果我们不需要父类的飞行方法,可以不调用 super.fly() 时,子类会完全覆盖父类的方法,这种情况下子类的方法独立于父类。
优缺点
- 虽然继承复用简单,易实现的优点,但是他也存在以下缺点:
- 1.继承破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的 ,也叫做
“白箱复用”
。例如,如果 Bird 类的 fly() 方法实现发生变化,Duck 类的行为也可能发生变化,这会给系统带来不必要的风险。 - 2.子类与父类的耦合度高。父类实现的任何改变都会导致子类的实现发生改变,不利于类的扩展和维护。
- .限制了复用的灵活性。比如,在代码中,Duck 类只能继承 Bird 类,无法动态决定是否继承其他类或选择不同的行为组合。如果我们希望 Duck 类可以灵活地选择不同的飞行和游泳实现,继承就显得不够灵活。相比之下,组合复用(如委托给接口或不同的类)能够在运行时根据需要灵活调整行为。
- 下面我们将通过组合复用来实现鸭鸭的飞和游的行为。
- 1.继承破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的 ,也叫做
含义
合成复用原则(Composition)
:是指通过将现有类的功能组合在一起,而不是通过继承来实现复用。也就是说,类的功能并不直接通过继承而获得,而是通过将其他类的实例作为成员变量,将其方法委托给这些成员来实现复用。
UML图
- 这幅图中 Duck 类实现了 Flyable 和 Swimmable 接口,并通过 合成复用的方式,将 Bird 类的飞行行为和 Fish 类的游泳行为组合进来。具体做法是:Duck 类在其构造器中通过依赖注入的方式接收 Flyable 和 Swimmable 对象(即 Bird 和 Fish),并将行为的实现委托给这些对象。
实现代码
- 行为的实现接口
package principlesposition_Reuse.after;
public interface Flyable {
void fly();
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.after;
public interface Swimmable {
void swim();
}
- 实现的类
package principlesposition_Reuse.after;
// 具体行为实现
class Bird implements Flyable {
public void fly() {
println("Bird is flying");
}
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.after;
class Fish implements Swimmable {
public void swim() {
println("Fish is swimming");
}
}
代码语言:javascript代码运行次数:0运行复制package principlesposition_Reuse.after;
// Duck 类表示一个鸭子,它实现了飞行和游泳的行为。
// 通过合成复用的方式,Duck 类将飞行和游泳的行为委托给 Bird 和 Fish 类。
class Duck implements Flyable, Swimmable {
private Flyable flyable; // 用于保存飞行行为
private Swimmable swimmable; // 用于保存游泳行为
// 构造器注入飞行和游泳的实现类
public Duck(Flyable flyable, Swimmable swimmable) {
this.flyable = flyable;
this.swimmable = swimmable;
}
// 实现 Flyable 接口的 fly 方法,委托给 flyable 的 fly 方法
// Duck 类不需要直接实现飞行的逻辑,只需要委托 Bird 类来执行飞行的具体操作。
@Override
public void fly() {
println("鸭鸭会飞其委托给了 ---> ");
flyable.fly(); // 委托飞行行为的实现
}
@Override
public void swim() {
println("鸭鸭会游其委托给了 ---> ");
swimmable.swim(); // 委托游泳行为的实现
}
}
- 测试代码
package principlesposition_Reuse.after;
// 测试代码
public class Main {
public static void main(String[] args) {
// 创建飞行和游泳的实现对象
Flyable bird = new Bird(); // 让 Bird 实现飞行
Swimmable fish = new Fish(); // 让 Fish 实现游泳
// 创建 Duck 对象,将飞行和游泳行为组合
Duck duck = new Duck(bird, fish);
// 测试 duck 的行为
duck.fly(); // 输出: Bird is flying
duck.swim(); // 输出: Fish is swimming
}
}
运行结果及解释
- 从运行结果我们可以看到鸭鸭实现了飞和游的行为,并且这些行为的体现是通过 Bird 和 Fish 去体现的。
合成复用的优点
- 组合而非继承:Duck 类不直接继承 Bird 或 Fish,而是通过组合的方式委托它们的行为。这避免了继承关系带来的耦合性,增强了灵活性和可扩展性。
- 行为复用:Duck 类通过组合 Flyable 和 Swimmable 接口的具体实现(Bird 和 Fish),实现了飞行和游泳行为的复用,而无需重新实现这些行为的具体细节。
- 灵活的扩展:如果以后需要给 Duck 添加新的行为,只需要修改组合的类(比如换成其他实现了 Flyable 或 Swimmable 的类)即可,而不需要修改 Duck 类本身
- 通过 合成复用,Duck 类将飞行和游泳的行为委托给了 Bird 和 Fish 类。这种设计方式比继承更加灵活,减少了类之间的耦合,增强了复用的灵活性和可扩展性。
合成复用与继承复用:适用场景和优缺点
合成复用
适用场景
- Has-A 关系
合成复用适用于类之间存在 “有一个”(Has-A)关系的情况。即,一个类通过包含其他类的实例来复用功能,而不是继承。例如:
Car
类有一个Engine
类,这时Car
类并不是Engine
类的子类,而是包含了一个Engine
实例。
- 行为变化
当一个类需要灵活地组合多个不相关的行为时,可以考虑使用合成复用。通过组合不同的行为,类可以灵活地选择并实现不同的功能,而不必受限于单一的继承体系。例如:
Duck
需要同时拥有飞行和游泳的行为。不同的行为可以分别来自Bird
和Fish
,这时可以通过合成复用来组合不同的行为实现。
优缺点
- 优点:
- 低耦合:类之间通过组合关系而非继承,降低了耦合度。
- 灵活性:合成复用能够在运行时动态组合不同的行为,提高了系统的灵活性。
- 可扩展性好:可以随时扩展新的行为,而无需改变现有的类。
- 缺点:
- 需要更多类和对象:可能会导致系统中出现更多的类和对象,增加了代码的复杂度。
- 额外的委托开销:在组合的过程中,可能需要通过委托来调用其他类的行为,增加了性能开销。
继承复用
适用场景
- Is-A 关系
继承复用适用于类之间存在 “是一个”(Is-A)关系的情况。即,子类是父类的一种特殊类型,并且在子类中需要复用父类的功能。例如:
Dog
是Animal
的一种,“狗是动物”这个关系表明Dog
可以继承自Animal
。
- 共享实现
如果子类与父类共享大量相同的实现,并且这个实现逻辑在子类中不需要改变时,继承是一种简洁的方式。父类提供通用的功能,子类可以直接复用。例如:
Car
类和Truck
类都可以继承自Vehicle
类,复用Vehicle
类中通用的功能。
优缺点
- 优点:
- 简洁:继承可以减少代码重复,子类可以直接复用父类的属性和方法。
- 高效:继承使得父类的实现可以直接复用,减少了额外的代码和类的创建。
- 缺点:
- 耦合度高:子类与父类紧密耦合,父类的改变会影响所有子类。
- 不灵活:继承是静态的,一旦继承关系确定,无法动态改变。
- 继承层次深:继承层次过深会导致代码的复杂性增加,使得维护和扩展变得更加困难。
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上传时间: 2025-07-25 15:18:18
推荐阅读
留言与评论(共有 5 条评论) |
本站网友 脸部整形 | 1分钟前 发表 |
并将行为的实现委托给这些对象 | |
本站网友 php数组 | 12分钟前 发表 |
复用 Vehicle 类中通用的功能 | |
本站网友 比特病毒 | 4分钟前 发表 |
在代码中 | |
本站网友 碱性食品 | 24分钟前 发表 |
而不必受限于单一的继承体系 |