The problem is this: I have an algorithm, and there are 2 different implementations of the algorithm. These implementations must be called from many places depending on the mode selected by the user. It would not be desirable in all places where implementations are called to write conditional statements. Therefore, I created an abstract class, and implementations inherit from it. In one place I check this:
if(firstMode){ list = new ListForm1(); } else{ list = new LiastForm2(); }
And then in all places I take full advantage of polymorphism. I would like to get rid of inheritance for three reasons:
- They constantly say that composition is always better than inheritance.
- The first form of the algorithm is much simpler than the second. There are only 3 methods in it, and 15 in the second. I had to include all 15 in the abstract class (well, there are 5 more common methods there). It turns out that 12 methods are not used by the first form.
- Theoretically, a new form of the algorithm may appear, which will have even less in common with the other two, but it will introduce 10 new methods and all of them will have to be added to the abstract class.
Pattern strategy, as I understand it, does not make much sense here. I will give his example from Wikipedia to better describe my doubts:
// Класс реализующий конкретную стратегию, должен реализовывать этот интерфейс // Класс контекста использует этот интерфейс для вызова конкретной стратегии interface Strategy { int execute(int a, int b); } // Реализуем алгоритм с использованием интерфейса стратегии class ConcreteStrategyAdd implements Strategy { public int execute(int a, int b) { System.out.println("Called ConcreteStrategyAdd's execute()"); return a + b; // Do an addition with a and b } } class ConcreteStrategySubtract implements Strategy { public int execute(int a, int b) { System.out.println("Called ConcreteStrategySubtract's execute()"); return a - b; // Do a subtraction with a and b } } class ConcreteStrategyMultiply implements Strategy { public int execute(int a, int b) { System.out.println("Called ConcreteStrategyMultiply's execute()"); return a * b; // Do a multiplication with a and b } } // Класс контекста использующий интерфейс стратегии class Context { private Strategy strategy; // Constructor public Context() { } // Set new strategy public void setStrategy(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int a, int b) { return strategy.execute(a, b); } }
All the same problems remain. Strategies then need to be related. If you connect them to the interface, rather than an abstract class, then only worse. The interface will still be very many methods, with the first form of the algorithm, many of them will not be needed. In addition, it is necessary to duplicate the common methods in all strategies; they will no longer be able to be put into the interface.
But I don’t understand how to use the composition here. In my understanding of the strategy in the pattern, the composition is already used. In the class Context
. It also contains the Strategy
class variable. Although it is possible delegation.
In general, the question is:
Can I get rid of all the above problems (abstract class overloaded with methods, strong coherence, which may make it difficult to add a new form of the algorithm), but still use conditional operators only in one place and not in all cases when I need one or another form of the algorithm (because so they are duplicated throughout the program).