为什么建议多用组合少用继承

在面向对象编程中,组合(Composition)和继承(Inheritance)是两种实现代码复用的基本方法。以下是为什么通常建议多用组合而少用继承的一些原因:

灵活性与可扩展性

  1. 松耦合:组合通过将一个类的功能委托给另一个类来实现,而不是通过继承。这样,类之间的耦合度较低,修改一个类不会影响另一个类,使系统更灵活。
  2. 动态行为改变:组合允许在运行时改变行为,可以通过替换被组合的对象来改变功能,而继承则在编译时决定行为,缺乏灵活性。

代码复用与维护

  1. 避免复杂的继承层次:继承层次结构容易变得复杂和难以维护,特别是在多层继承时。而组合则能通过简单的对象组合来实现复杂功能,避免了复杂的继承层次。
  2. 增加代码复用:通过组合,可以重用已有的类而不需要创建新的子类,从而减少代码重复,提高代码复用性。

设计原则与模式

  1. 遵循“组合优于继承”原则:这是设计模式中的一个重要原则,强调优先使用组合而不是继承来实现代码复用和功能扩展。
  2. 符合开闭原则(OCP):使用组合更容易实现对扩展开放、对修改关闭的原则。新增功能可以通过组合新的类来实现,而不需要修改现有类。

避免继承问题

  1. 菱形继承问题:多重继承会导致菱形继承问题,即同一基类被多次继承,导致歧义和复杂性。组合则不存在这个问题,因为它是通过对象的关联来实现的。
  2. 基类变更影响:在继承关系中,如果基类发生变化,会影响所有子类。组合则相对独立,修改一个类不会直接影响组合它的类。

实际应用中的案例

  1. 策略模式:通过组合不同的策略对象,动态地改变算法或行为。
  2. 装饰者模式:通过组合多个装饰者对象,动态地为对象增加功能。

代码案例

背景

设计一个绘图应用程序,需要有不同形状的类,比如圆形(Circle)、矩形(Rectangle)等,并且这些形状可以有不同的颜色和边框样式。

使用继承实现
abstract class Shape {
    public abstract void draw();
}

class Circle extends Shape {
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle extends Shape {
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
}

class RedCircle extends Circle {
    public void draw() {
        System.out.println("Drawing a red circle");
    }
}

class BlueCircle extends Circle {
    public void draw() {
        System.out.println("Drawing a blue circle");
    }
}

class RedRectangle extends Rectangle {
    public void draw() {
        System.out.println("Drawing a red rectangle");
    }
}

class BlueRectangle extends Rectangle {
    public void draw() {
        System.out.println("Drawing a blue rectangle");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape redCircle = new RedCircle();
        redCircle.draw();
        
        Shape blueRectangle = new BlueRectangle();
        blueRectangle.draw();
    }
}


这种设计的问题在于每增加一种新的形状或颜色都需要创建新的子类,类的数量会迅速增长,维护和扩展变得困难。

使用组合实现

通过组合,我们可以更灵活地设计这个系统。我们可以将颜色和形状的概念分离

// 颜色接口
interface Color {
    void applyColor();
}

class RedColor implements Color {
    public void applyColor() {
        System.out.println("Applying red color");
    }
}

class BlueColor implements Color {
    public void applyColor() {
        System.out.println("Applying blue color");
    }
}

// 形状抽象类
abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    abstract void draw();
}

class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    public void draw() {
        System.out.print("Drawing a circle with ");
        color.applyColor();
    }
}

class Rectangle extends Shape {
    public Rectangle(Color color) {
        super(color);
    }

    public void draw() {
        System.out.print("Drawing a rectangle with ");
        color.applyColor();
    }
}

public class Main {
    public static void main(String[] args) {
        Shape redCircle = new Circle(new RedColor());
        redCircle.draw();
        
        Shape blueRectangle = new Rectangle(new BlueColor());
        blueRectangle.draw();
    }
}

分析

在这个设计中,我们使用了组合(Composition)而不是继承来实现颜色和形状的结合:

  • 颜色:我们定义了Color接口和它的实现类RedColor和BlueColor。
  • 形状:我们定义了Shape抽象类,并将Color作为一个组合成员。然后,我们创建了具体的形状类Circle和Rectangle。

这样,我们可以任意组合形状和颜色,而不需要创建大量的子类。新增一种颜色或形状只需要创建一个新的实现类,而不需要修改现有的代码。这种设计更加灵活和可扩展,遵循了“组合优于继承”的设计原则。

总结

虽然继承在某些情况下仍然有用,但在大多数情况下,组合提供了更高的灵活性、可扩展性和可维护性。因此,建议在设计系统时,多使用组合,少使用继承,以构建更健壮和灵活的系统。

持续输出 欢迎关注

搜索框传播样式-白色版

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
多用组合少用继承的设计思想是一种常见的设计原则,也被称为组合优于继承(Composition over Inheritance)原则。它建议在设计类和对象之间的关系时,更多地使用组合而不是继承。 使用组合意味着将功能从一个类提取出来,并将其作为另一个类的成员进行组合。这样做可以避免继承链的复杂性和耦合度的增加,同时也提供了更大的灵活性和可维护性。下面是一些使用组合而不是继承的好处: 1. 松耦合性:组合减少了类之间的依赖关系,使得系统更加灵活和可扩展。如果使用继承,子类与父类之间的耦合度会增加,当父类发生改变时,子类也需要相应地进行修改。 2. 更好的代码复用:通过将功能封装为独立的类,可以更方便地在不同的类中进行复用。这样可以避免重复编写相似的代码,并且更容易调整和修改功能。 3. 更好的可维护性:使用组合可以将系统分解为更小、更简单的部分,每个部分都可以独立地进行修改和测试。这样可以提高代码的可读性和可维护性,减少出错的可能性。 4. 灵活的设计扩展:使用组合可以轻松地在运行时更改对象的行为,而无需修改类的结构。这种灵活性使得系统更容易适应变化和需求的变化。 当然,并不是说继承完全不应该使用,继承仍然是一种有用的工具。但在设计中,应该优先考虑使用组合,只有在确实需要共享代码和行为的情况下才考虑使用继承
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值