3

I have an algorithm, and I have 2 different implementations of the algorithm. These implementations should be called from many places, depending on the mode selected by the user. I wouldn't like to write conditional statements at all places where implementations called. So, I create an abstract class and Implementations inherit it. I can set the desired mode in one place like this:

if(firstMode){
    list = new ListForm1();
}
else{
    list = new LiastForm2();
}

And after that in all other places I can enjoy all the benefits of polymorphism. It works good but I want to get rid of the inheritance of the following reasons:

  1. I heard that composition is much better than inheritance.
  2. The first form of the algorith is much easier then the second form. In the first form I have only 3 methods and in second form I have 15 methods. The abstract class had to include all 15 (and 5 common methods). It turns out that the 12 methods not using by the first form.
  3. Theoretically, there may be a new form of the algorithm, which will have even less in common with the other two, but it will bring 10 new methods and all of them will have to add an abstract class.

The Strategy Pattern, as I understand, does not make sense to use here. Here is the example of Strategy 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);
    }
}

It has the same problems. Strategies should be linked with each other. If I link them with the interface instead of an abstract class it will be even worse. Interface will contain a lot of methods but many of them will not be needed for the first form of the algorithm. In addition, general methods have to duplicate in all concrete strategies. I can not provide a default implementation in the interface.

Moreever, I don't understand how to use composition here. As I understand, Strategy Pattern already used composition. Class Context includes the instance of Strategy as a field. But maybe it is delegation.

So, here is my question:

Can I get rid of all the above problems (too many methods of an abstract class, the strong connection, because of which it will be difficult to add a new form of an algorithm), but still use conditional statements in only one place, not in all cases when I need some form of algorithm.

UPD: I want to show how I called some methods, which implemented in SECOND form of the algorithm, but not need for the FIRST form of algorithm:

if (list.getCurrentLeaders().contains(ballIdx))

The default implementation of method getCurrentLeaders() return null. So, if I called it with instance of the FIRST form of the algorithm then I will get an error. I understand that it is bad. But how can I solve it?

  • 3
    What do you mean by "Strategies should be linked with each other."? At the moment, your question is fairly unclear. It sounds like you may well want an interface for the public API (i.e. considering what the *caller* should see), but then you may well want an abstract class to act as a base for implementations which share a lot of details. It's hard to say while it's all so abstract. Note that "favour composition" doesn't mean "inheritance always sucks". – Jon Skeet Mar 31 '16 at 07:48
  • _I heard that composition is much better than inheritance._ Inheritance has its place. You should not simply throw it away because _Y_ is better (for case _Z_). Could you clear up what you mean by Algorithm #1 has X methods and #2 has Y methods? Can it be changed so that the caller in both cases simply calls one method and is implementation independent? – Michael Lloyd Lee mlk Mar 31 '16 at 07:50
  • I don't understand how do you use your form - if one has 15 methods and second has 5 - (so I assume there are 10 empty methods in second) - what happens when they are called in application? – AdamSkywalker Mar 31 '16 at 07:56
  • I mean what is the public API of both algorithms? how many methods does it have? how is it used? – AdamSkywalker Mar 31 '16 at 07:57
  • @JonSkeet, sorry for my English. When I say "Strategies should be linked with each other" I mean that they must have the same interface. – Александр Елизаров Mar 31 '16 at 08:50
  • @AdamSkywalker, yes there are 10 empty methods in second form. When they should be called in the application nothing happened. I understand that it is bad. But I don't know how to solve it. – Александр Елизаров Mar 31 '16 at 08:52
  • @АлександрЕлизаров so I guess that all 15 methods from first form are called somewhere in your app? -> your app is tightly coupled with algorithm details? can you post real code somewhere so I could see how it could be avoided? – AdamSkywalker Mar 31 '16 at 08:58
  • @AdamSkywalker, of course I can, thank you. I added my question to show some code, when I called method. – Александр Елизаров Mar 31 '16 at 10:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107840/discussion-between-adamskywalker-and--). – AdamSkywalker Mar 31 '16 at 10:42
  • Have a look at this question : http://stackoverflow.com/questions/370258/real-world-example-of-the-strategy-pattern/35180265#35180265 – Ravindra babu Mar 31 '16 at 19:07

5 Answers5

1

Starting from the beginning in the case you need to call a different algorithm based on a different mode chosen by the user you could create a kind of factory class to supply the algorithm throughout your code. I think that if it is only an algorithm and if you are on Java 8 you can use a Function or a Predicate or a Supplier in combination with a map to avoid the if statement, for example :

Map<String, Predicate<Whatever>> map = new HashMap<>();
map.put("mode_one", (w) -> true);
map.put("mode_two", (w) -> false);

Then to call the algorithm, simply :

map.get("mode_one").test()

In the case you need to supply a different form like in the example you posted, you could use a Supplier instead of a predicate. Based on your simple requirement, I think that going functional would be the best bet ...

aleroot
  • 71,077
  • 30
  • 176
  • 213
1

If you are not implementing all the methods (ie. if you have 15 methods in the abstract class to be implemented, and you only need to implement 10), then you are breaking the Liskov Substitution Principle :

https://en.wikipedia.org/wiki/Liskov_substitution_principle

Basically, that is a bad thing.

Try and convert the non-common methods into some other kind of object that gets passed into the constructor (on the abstract).

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225
1

I heard that composition is much better than inheritance.

Not always - many times inheritance is the right construct. You have to think about it in has a and is a terms. A football team has a collection pf players. It also has a coach, a schedule, a name, etc. So Team : List<Player> is not the right construct.

A Car is a Vehicle, so inheritance is the right construct.

So think about your design this way:

Do my classes share a common base? Is there a base class that makes sense to say ListForm1 is a ListBase and ListForm2 is a ListBase. What methods and properties are common to those types that should be in the case type? What methods and properties should be virtual so that I can override them?

The first form of the algorithm is much easier then the second form. In the first form I have only 3 methods and in second form I have 15 methods. The abstract class had to include all 15 (and 5 common methods). It turns out that the 12 methods not using by the first form.

So maybe your base type only 3 methods, and you add methods in the sub-types as necessary. Remember that you can have multiple base types in the chain, but it's a chain, not a tree, meaning you can have a single parent that has another parent, but you can't have two parents.

Or maybe you have orthogonal interfaces since you can implement multiple interfaces.

Theoretically, there may be a new form of the algorithm, which will have even less in common with the other two, but it will bring 10 new methods and all of them will have to add an abstract class.

Why? Why can't the new algorithm just define its own methods that it needs, so long as clients pick the appropriate level in the inheritance chain (or appropriate interface(s)) so that it knows what methods should be implemented.

if (list.getCurrentLeaders().contains(ballIdx))

The default implementation of method getCurrentLeaders() return null. So, if I called it with instance of the FIRST form of the algorithm then I will get an error. I understand that it is bad. But how can I solve it?

So do you need to check that this particular list implements an interface (or inherits a base class) that does implement that method?

Community
  • 1
  • 1
D Stanley
  • 149,601
  • 11
  • 178
  • 240
1

You can implement some kind of Chain Of Responsibility pattern.

interface IStrategy {
  void Run();
  bool CanHandle(IContext context);
}

class StrategyChecker {
  IStrategy GetStrategy(IContext context) {
    foreach(var strategy in strategies) {
      if(strategy.CanHandle(context)
        return strategy;
    }

    return defaultStrategy;
  }
}    

class Director {
  void Run() {
    strategyChecker.AddStrategy(strategy1);
    strategyChecker.AddStrategy(strategy2);

    var strategy = strategyChecker.GetStrategy(someContext);
    strategy.Run();
  }
}

Sorry for c# pseudo-code.

Dzianis Yafimau
  • 2,034
  • 1
  • 27
  • 38
  • 1
    Nice application of this chain of responsibility pattern. Please add NoneStrategy (Null Pattern) to the end of chain to avoid an exception. – Jian Huang Apr 13 '16 at 14:52
  • 1
    strategyChecker.AddStrategy(strategyNone); – Jian Huang Apr 13 '16 at 15:01
  • Yes, you're right! But it's just a quick sketch for my idea, you should adapt this "code" for your needs. BTW, there is defaultStrategy as NullPattern strategy – Dzianis Yafimau Apr 13 '16 at 16:24
0

Why not just use your IStrategy as a type?

interface IStrategy {
    int execute(int a, int b); 
}

class Strategy1 implements IStrategy {}
class Strategy2 implements IStrategy {}

static class StrategyFactory {
    IStrategy Create(bool first) {
        return first ? new Strategy1() : new Strategy2();
    }
}

And then in your user code:

void doStuff()
{
    IStrategy myStrategy = StrategyFactory.Create(true);
    myStrategy.execute(1, 2);
}
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135