一、核心思想与优势

  1. 核心思想
    优先使用对象组合(has-a)或聚合(contains-a)实现代码复用,而非继承(is-a)。通过将已有对象作为新对象的成员变量,动态调用其功能。

  2. 优势

    • 降低耦合度:组合关系隐藏了成员对象的内部细节(黑箱复用),减少类间的直接依赖。
    • 增强灵活性:可在运行时动态替换成员对象,无需修改原有代码(如依赖注入)。
    • 符合开闭原则:扩展新功能时,通常只需新增类,无需修改现有代码。

二、典型应用场景与示例

  1. 数据库连接管理
  • 问题:若UserDao直接继承DBConnection,切换数据库(如从MySQL改为Oracle)需修改继承关系,导致高耦合。
  • 合成复用实现
    // 定义接口
    interface DatabaseConnection {
        String getConnection();
    }
    
    // 具体实现类
    class MySQLConnection implements DatabaseConnection {
        public String getConnection() { return "MySQL连接"; }
    }
    
    // 组合使用
    class UserDao {
        private DatabaseConnection connection;
        
        public UserDao(DatabaseConnection connection) {
            this.connection = connection;
        }
        
        public void addData() {
            String conn = connection.getConnection();
            System.out.println("使用" + conn + "操作数据库");
        }
    }
    
    效果:新增OracleConnection时,只需注入不同实现,无需修改UserDao。

  1. 图形绘制系统
  • 问题:若通过继承实现不同图形(如圆形、矩形),新增“阴影效果”需为每种图形创建子类,导致类爆炸。
  • 合成复用实现
    // 定义图形接口
    interface Shape {
        void draw();
    }
    
    // 具体图形类
    class Circle implements Shape {
        public void draw() { System.out.println("绘制圆形"); }
    }
    
    // 组合装饰器
    class ShadowDecorator implements Shape {
        private Shape shape;
        
        public ShadowDecorator(Shape shape) {
            this.shape = shape;
        }
        
        public void draw() {
            shape.draw();
            System.out.println("添加阴影效果");
        }
    }
    
    效果:动态为任意图形添加阴影,无需修改原有类。

  1. 汽车分类管理
  • 问题:若通过继承按“动力源”(汽油/电动)和“颜色”(红/黑)组合子类,新增颜色或动力源需新增多个子类。
  • 合成复用实现
    // 组合属性
    class Car {
        private EnergySource energy;
        private Color color;
        
        public Car(EnergySource energy, Color color) {
            this.energy = energy;
            this.color = color;
        }
        
        public void move() {
            System.out.println(color.getName() + energy.getName() + "汽车行驶");
        }
    }
    
    // 动力源接口及实现
    interface EnergySource { String getName(); }
    class Gasoline implements EnergySource { public String getName() { return "汽油"; } }
    
    效果:新增动力源(如电力)只需实现EnergySource接口,无需修改Car类。

  1. 用户行为扩展(策略模式)
  • 问题:若Animal类直接包含固定行为(如狗吠、猫叫),新增行为需修改父类代码。
  • 合成复用实现
    // 行为接口
    interface SoundBehavior {
        void makeSound();
    }
    
    // 动态组合行为
    class Animal {
        private SoundBehavior behavior;
        
        public Animal(SoundBehavior behavior) {
            this.behavior = behavior;
        }
        
        public void performSound() {
            behavior.makeSound();
        }
    }
    
    // 具体行为类
    class Bark implements SoundBehavior {
        public void makeSound() { System.out.println("汪汪"); }
    }
    
    效果:通过注入不同SoundBehavior实现动态行为切换。

三、总结

合成复用原则通过对象组合替代继承,解决了继承导致的高耦合、低扩展性问题。典型应用包括:

  1. 依赖注入(如Spring中Controller注入Service)。
  2. 装饰器模式(动态扩展功能)。
  3. 策略模式(算法或行为的灵活替换)。
    实践建议:在设计时优先考虑“has-a”关系,仅在需要明确分类关系时(如子类是父类的逻辑扩展)使用继承。

更多推荐