Дублирование кода с композицией и шаблоном наблюдателя? - PullRequest
2 голосов
/ 26 июня 2019

Предположим, у меня есть два класса с нисходящими подписками (подписчиками)

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 заставляет меня не использовать абстрактный класс.Мне интересно, что здесь правильно?ясно вы видите, что есть дублирование кода с полным методом add для любого из A, B классов (и, возможно, больше в будущем).

Ответы [ 2 ]

1 голос
/ 26 июня 2019

Вы правы, что композиция над наследованием - важный принцип, о котором следует помнить; композиция часто лучше, потому что дает вам больше гибкости.

В этом смысле, на мой взгляд, абстрактный базовый класс является оправданным выбором. Подумайте над вопросом «является»: когда один класс расширяет другой класс, тогда существует отношение «есть», переходящее из подкласса в суперкласс. Ваши классы A и B - это то, на что вы можете подписаться, поэтому 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 не очень хорошо поддерживает это.

0 голосов
/ 27 июня 2019

Ваш пример не нарушает принцип СУХОЙ. Вы просто используете объект, который обещает обрабатывать подписки. Тонкий слой вокруг него не дублирует никаких знаний, он делегирует должным образом.

Другой подход, который вы можете использовать, - это сделать ваших клиентов (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;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...