【问题标题】:Distinguishing between delegation, composition and aggregation (Java OO Design)区分委托、组合和聚合(Java OO 设计)
【发布时间】:2010-11-25 22:43:00
【问题描述】:

我一直面临着如何区分委托、组合和聚合,并确定在哪些情况下最好使用其中一种。

我查阅了一本 Java OO 分析和设计书籍,但我的困惑仍然存在。主要解释是这样的:

委托:当我的对象按原样使用另一个对象的功能而不更改它时。

组成:我的对象由其他对象组成,这些对象在我的对象被销毁-垃圾收集后又不能存在。

聚合:我的对象由其他对象组成,这些对象即使在我的对象被销毁后仍然可以存活。

是否有可能有一些简单的例子来说明每个案例,以及它们背后的原因?除了我的对象简单地引用另一个对象之外,这些示例还能如何演示?

【问题讨论】:

    标签: java oop aggregation composition delegation


    【解决方案1】:

    在所有三种情况下,您的对象都会引用另一个对象。区别在于引用对象的行为和/或生命周期。一些例子:

    1. 组成:房子包含一个或多个房间。 Room 的生命周期由 House 控制,因为没有 House,Room 将不存在。

    2. 聚合:用积木建造的玩具屋。你可以拆卸它,但块会保留。

    3. 代表团:你的老板让你给他拿杯咖啡,你让实习生替你做。委派不是一种关联(就像组合/聚合一样)。后两者已在 Stack Overflow 上讨论过 many times

    在评论中,您询问每种情况下的实现有何不同,并观察到在所有情况下我们都会调用相关对象的方法。确实,在每种情况下,我们都会有这样的代码

    myRoom.doWork();
    
    myBlock.doWork();
    
    myMinion.doWork();
    

    但区别在于相关对象的生命周期和基数。

    对于组件,房间在房屋创建时就存在。所以我们可以在 House 的构造函数中创建它们。

    在关联的情况下(我将使用轮胎和汽车)汽车可能会在其构造函数中添加轮胎,但稍后您可能想要移除和更换轮胎。所以你也有诸如

    之类的方法
     removeTyre(FrontLeft)
     addNewTyre(aTyre, BackRight)
    

    aTyre 对象很可能来自工厂——我们在 Car 的任何方法中都没有new 它。

    在委托的情况下,您甚至可能没有一个成员变量来保存委托

     resourcingPool().getIntern().getCoffee(SkinnyLatte, workstation 7);
    

    对象之间的关系只在实习生拿咖啡时才持续。然后返回资源池。

    【讨论】:

    • 感谢您指出之前的讨论。那么,就代码的外观而言,所有 3 种情况应该看起来几乎相同?引用其他对象?
    • 或多或少。在委托的情况下,可以从其他地方获得引用(您甚至可以委托静态方法);在组合的情况下,嵌套对象由父对象创建或在其帮助下创建(因为它控制它们的生命周期);并且在聚合嵌套对象实例的情况下被注入(通常在构造/初始化期间)。
    【解决方案2】:

    你的书解释得很好,所以让我详细说明并提供一些例子。

    委托:当我的对象按原样使用另一个对象的功能而不更改它时。

    有时一个类在逻辑上可能需要很大。但是大类并不是一个好的编码实践。有时,一个类的某些功能可能会以不止一种方式实现,您可能希望在某个时候改变它。

    
    class FeatureHolder {
     void feature() {
      // Big implementation of the feature that you dont want to put in the class Big
     }
    }
    
    class Big {
     private FeatureHolder FH = new FeatureHolder();
    
     void feature() {
      // Delegate to FeatureHolder.
      FH.feature();
     }
    
     //.. Other features
    }
    

    从上面的例子中,Big.feature() 按原样调用 FH 的特征而不改变它。这样,Big 类就不需要包含特性的实现(分工)。此外,feature() 可以由其他类(如“NewFeatureHolder”)以不同方式实现,Big 可能会选择使用新的特征持有者。

    组成:我的对象由其他对象组成,这些对象在我的对象被销毁-垃圾收集后又不能存在。

    聚合:我的对象由其他对象组成,即使在我的对象被销毁后也可以存活。

    从技术上讲,组合是“一部分”,聚合是“引用”关系。你的手臂是你的一部分。如果你不再活着,你的手臂也会死。你的衣服不是你的一部分,但你拥有它们;你可以请客,你的衣服不会随身携带。

    在编程中,一些对象是另一个对象的一部分,没有它它们就没有逻辑意义。例如,一个按钮被组合成一个窗口框架。如果框架关闭,按钮就没有理由再存在了(组合)。一个按钮可能引用了一个数据库(比如刷新数据);当按钮被消除时,数据库可能仍然存在(聚合)。

    对不起我的英语,希望这对你有帮助

    【讨论】:

      【解决方案3】:

      代表团

      public class A {
        private B b = new B();
      
        public void methodA() {
          b.methodB();
        }
      }
      

      A 的客户调用methodA 时,A委托调用BmethodB

      基本原理。 A 类公开了属于其他地方的行为。这可能发生在单继承语言中,其中类 A 继承自一个类,但其客户端需要在不同类中实现的行为。 Further study.

      混合委派

      public class A {
        private B b = new B();
      
        public void methodA() {
          b.methodB( this );
        }
      }
      

      涉及简单转发的委托和替代继承的委托的区别在于被调用者必须接受调用者的参数,例如:

          b.methodB( this );
      

      基本原理。 允许类B 实例使用类A 提供的功能,就像类B 继承自类A 一样——但没有继承。 Further study.

      作曲

      public class A {
        private B b = new B();
      
        public A() {
        }
      }
      

      一旦不再存在对类 A 的特定实例的引用,它的类 B 实例就会被销毁。

      基本原理。 允许类以模块化方式定义行为和属性。 Further study.

      聚合

      public class A {
        private B b;
      
        public A( B b ) {
          this.b = b;
        }
      }
      
      public class C {
        private B b = new B();
      
        public C() {
          A a = new A( this.b );
        }
      }
      

      一旦不再引用类A 的特定实例,它的类B 实例将不会被销毁。在此示例中,AC 都必须在 B 被销毁之前进行垃圾回收。

      基本原理。 允许实例重用对象。 Further study.

      没有参考的演示

      这些简单模式的名称由它们的引用关系定义。

      【讨论】:

        【解决方案4】:

        1) 委派:人-司机-车示例。一个男人买了一辆车。但是那个人不知道开车。所以他会指定一个会开车的司机。所以 Man 类想要使用汽车进行运输。但它不具备与汽车的交互功能/兼容性。所以他使用了一个与汽车兼容的类,即与人类兼容的驱动程序。假设司机能听懂人说什么

        2) 组成:汽车模拟是一个例行的例子。为了使汽车移动,车轮会旋转。汽车类使用轮类旋转功能作为其移动功能的一部分,其中轮是汽车的一部分。

        3) 聚合:汽车及其颜色。汽车类对象法拉利将有一个颜色类对象红色。但是,当用户使用红色规范进行搜索时,颜色类对象 red 可以作为单独的类存在。

        【讨论】:

          【解决方案5】:

          我可以用一个非常简单的句子说:

          委托是:在您不想更改时将行为委托给其他类。通过更改,我的意思是在运行时。例如,您将司机委派给司机在驾驶时不会更改的汽车类。

          组合是:当您想要使用在运行时可能会更改的一系列类(一个或多个实现接口的类)的行为时。但是您应该考虑这些类不能在没有主要类的情况下存在,例如酒店的房间。如果您删除酒店,酒店的所有房间都将不存在。

          聚合是:与组合相同,但类可以在没有主类的情况下存在。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-06
            • 2011-01-09
            • 2018-10-11
            • 1970-01-01
            • 1970-01-01
            • 2023-03-21
            相关资源
            最近更新 更多