У меня есть алгоритм, и у меня есть две различные реализации алгоритма. Эти реализации следует вызывать из многих мест, в зависимости от выбранного пользователем режима. Я бы не хотел писать условные утверждения во всех местах, где вызывались реализации. Итак, я создаю абстрактный класс, а реализация наследует его. Я могу установить нужный режим в одном месте, как это:Как избавиться от наследства?
if(firstMode){
list = new ListForm1();
}
else{
list = new LiastForm2();
}
И после того, что во всех других местах, где я могу пользоваться всеми преимуществами полиморфизма. Это работает хорошо, но я хочу, чтобы избавиться от наследования по следующим причинам:
- Я слышал, что композиция гораздо лучше, чем наследование.
- Первая форма алгоритма намного проще, чем вторая форма. В первой форме у меня всего 3 метода, а во второй форме у меня 15 методов. В абстрактный класс должны были входить все 15 (и 5 общих методов). Оказывается, что 12 методов не используются первой формой.
- Теоретически, может быть новая форма алгоритма, которая будет иметь еще меньше общего с другими двумя, но она принесет 10 новых методов, и все они должны будут добавить абстрактный класс.
Шаблон стратегии, как я понимаю, не имеет смысла использовать здесь. Вот пример стратегии Pattern:
//abstract strategy
interface Strategy {
int execute(int a, int b);
}
// concrete strategy1
class ConcreteStrategyAdd implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}
// concrete strategy2
class ConcreteStrategySubtract implements Strategy {
public int execute(int a, int b) {
return a - b;
}
}
//concrete strategy3
class ConcreteStrategyMultiply implements Strategy {
public int execute(int a, int b) {
return a * b;
}
}
class Context {
private Strategy strategy;
public Context() {
}
// Set new concrete strategy
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
// use strategy
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}
Он имеет те же проблемы. Стратегии должны быть связаны друг с другом. Если я свяжу их с интерфейсом вместо абстрактного класса, это будет еще хуже. Интерфейс будет содержать множество методов, но многие из них не понадобятся для первой формы алгоритма. Кроме того, общие методы должны дублироваться во всех конкретных стратегиях. Я не могу обеспечить реализацию по умолчанию в интерфейсе.
Более того, я не понимаю, как использовать композицию здесь. Насколько я понимаю, Strategy Pattern уже использовал композицию. Контекст класса включает в себя экземпляр стратегии как области. Но, возможно, это делегирование.
Итак, вот мой вопрос:
Могу ли я избавиться от всех вышеперечисленных проблем (слишком много методов абстрактного класса, сильной связи, из-за чего будет трудно добавить новую форму алгоритма), но все же использовать условные операторы только в одном месте, а не во всех случаях, когда мне нужен какой-то алгоритм.
UPD: Я хочу, чтобы показать, как я назвал некоторые методы, которые реализованы в ВТОРЫХ виде алгоритма, но не нужен для первой формы алгоритма:
if (list.getCurrentLeaders().contains(ballIdx))
реализации по умолчанию способ getCurrentLeaders()
возвращение null. Итак, если я назвал его с экземпляром FIRST-формы алгоритма, то я получу ошибку. Я понимаю, что это плохо. Но как я могу это решить?
Что вы подразумеваете под «Стратегии должны быть связаны друг с другом»?? На данный момент ваш вопрос довольно неясен. Похоже, вам может понадобиться интерфейс для публичного API (т. Е. С учетом того, что должен видеть вызывающий * *), но тогда вам может потребоваться, чтобы абстрактный класс выступал в качестве базы для реализаций, которые разделяют множество деталей. Трудно сказать, пока все это настолько абстрактно. Обратите внимание, что «предпочтение композиции» не означает, что «наследование всегда отстой». –
_I слышал, что композиция намного лучше, чем наследование. Наследование имеет свое место. Вы не должны просто выбросить его, потому что _Y_ лучше (для случая _Z_). Не могли бы вы прояснить, что вы подразумеваете под алгоритмом №1, есть методы X, а # 2 - методы Y? Можно ли его изменить так, чтобы вызывающий в обоих случаях просто вызывал один метод и независим от реализации? –
Я не понимаю, как вы используете свою форму - если у вас 15 методов, а у второго есть 5 - (поэтому я предполагаю, что во втором - 10 пустых методов) - что происходит, когда они вызываются в приложении? – AdamSkywalker