【问题标题】:Code duplication with composition and observer pattern?具有组合和观察者模式的代码重复?
【发布时间】:2019-06-26 07:54:17
【问题描述】:

假设我有两个具有下游订阅(订阅者)的类

class A {
   SubscriptionManager<A> subscriptionManager; // downstream subscriptions
   void addSub(Subscription<A> sub){
      subscriptionManager.addSub(sub);
   }
}

class B {
   SubscriptionManager<B> subscriptionManager; // downstream subscriptions
   void addSub(Subscription<B> sub){
      subscriptionManager.addSub(sub);
   }
}

这是我正在处理的问题,它是一个设计问题。我听说过多次组合优于继承,在这样的示例中,我可以创建一个包含订阅管理器并具有添加和删除订阅者功能的抽象类。

但是,compoisiton over inheritance 让我不使用抽象类。我想知道这里什么是正确的?很明显,您会看到 A, B 类中的任何一个的整个 add 方法都存在代码重复(将来可能会更多)。

【问题讨论】:

    标签: java oop


    【解决方案1】:

    你说得对,composition over inheritance 是一个需要牢记的重要原则;组合通常更好,因为它为您提供了更大的灵活性。

    尽管如此,在我看来,抽象基类是一个合理的选择。想想“是”的问题:当一个类扩展另一个类时,从子类到超类存在“是”的关系。您的课程AB 都是您可以订阅的,所以A Subscribable

    abstract class Subscribable<T> {
        private SubscriptionManager<T> subscriptionManager;
    
        protected Subscribable(SubscriptionManager<T> subscriptionManager) {
            this.subscriptionManager = subscriptionManager;
        }
    
        void addSub(Subscription<T> sub) {
            subscriptionManager.addSub(sub);
        }
    }
    
    class A extends Subscribable<A> {
        public A(SubscriptionManager<A> subscriptionManager) {
            super(subscriptionManager);
        }
    }
    
    class B extends Subscribable<B> {
        public B(SubscriptionManager<B> subscriptionManager) {
            super(subscriptionManager);
        }
    }
    

    我想知道这里什么是正确的?

    这些都是设计选择,很少有单一的、客观正确的选择 - 每个设计选择都有自己的优点和缺点。

    一些 OO 编程语言支持mixins,它可以帮助您通过组合而不是继承来实现类似的东西,但 Java 对此支持得不是很好。

    【讨论】:

    • 这只是一个例子。总的来说,我觉得组合优于继承会在某些情况下违反 DRY。
    【解决方案2】:

    您的示例不违反 DRY 原则。您只是在使用一个承诺处理订阅的对象。它周围的薄层没有复制任何知识,它正在适当地委派。

    您可以采取的另一种方法是让您的客户(A 和 B)成为将生成 SubscriptionManager 的具体工厂。这样他们的客户就可以直接与经理进行交互,而您不必编写包装方法。

    class A {
       SubscriptionManager<A> subscriptionManager; // downstream subscriptions
    
       /**
        * There is some tension with Law of Demeter here,
        * but these are the decisions you have to make as a designer. 
        */
       SubscriptionManager<A> subManager() {
          //note: SubscriptionManager should be abstract to avoid tight coupling.
          return subscriptionManager;
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 2023-04-10
      相关资源
      最近更新 更多