12

I've started looking into Design Patterns recently, and one thing I'm coding would suit the Strategy pattern perfectly, except for one small difference.

Essentially, some (but not all) of my algorithms, need an extra parameter or two passed to them.

So I'll either need to

  • pass them an extra parameter when I invoke their calculate method

or

  • store them as variables inside the ConcreteAlgorithm class, and be able to update them before I call the algorithm.

Is there a design pattern for this need / How could I implement this while sticking to the Strategy Pattern?

I've considered passing the client object to all the algorithms, and storing the variables in there, then using that only when the particular algorithm needs it. However, I think this is both unwieldy, and defeats the point of the strategy pattern.

Just to be clear I'm implementing in Java, and so don't have the luxury of optional parameters (which would solve this nicely).

2
  • Optional parameters like in C++ would solve nothing, as they're just a shorthand for defining multiple overloaded methods.
    – maaartinus
    Mar 13, 2011 at 15:20
  • I'd try hard to avoid storing the additional parameters somewhere where I had to change them before use. This way you make ConcreteAlgorithm stateful, so it can't be passed easily to other method or threads. Moreover, it's too easy to forget to set the parameters.
    – maaartinus
    Mar 13, 2011 at 16:39

5 Answers 5

7

You need to clarify your strategy.

It all depends on how you use your algorithms. For your client class to use different strategy implementations interchangeably, they all need to have a common abstraction. If they don't follow the same interface, maybe what you need are different abstractions.

I've used configurable strategies before, where you parameterize the concrete classes on construction:

interface Strategy {
  int calculate();
}

class ConcreteStrategyThatNeedsAParameter implements Strategy {
  private final int param;
  public ConcreteStrategyThatNeedsAParameter(int param) {
    this.param = param;
  }
  public int calculate() { 
    // uses param...
  }
}

Now, someone still needs to create an instance of this class and pass it to your client. But your client still only needs to know about the Strategy interface.

It also works if your strategy method takes parameters, but then your client knows about those parameters and passes them to all implementations it works with.

1
  • The client is the one with the context to provide the parameter. Oct 10, 2016 at 15:49
6

Samuel, is it possible to encapsulate the parameter that each of the strategies take into one common class and then extend that common Parameter class to add more behavior that some of your strategies specifically need?

E.g.

StrategyParameter //Base strategy parameter that most of the strategies need
        ^
        |
        |
SpecialStrategyParameter // will be used for strategies that need more parameter

And then, define strategy hierarchy like:

Interface MyStrategy {
   void myStrategyMethod(StrategyParameter parameter);
}

class MyNormalStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

call the above strategy as: myNormalStrategyInstance.myStrategyMethod(strategyParameter);

class MySpecializedStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

call the above strategy by passing SpecialStrategyParameter instance instead like: mySpecializedStrategy.myStrategyMethod(specialStrategyParameter);

Please update if something is not clear. Will be happy to explain/clarify.

3
  • 2
    -1 requires downcast, breaks encapsulation of design. Though it is an improvement on the design in the question, there are better ways to skin this cat.
    – tallseth
    Aug 7, 2013 at 12:34
  • @tallseth I see downcast too. But I don't see better ways. Could you please point out a better solution? An article or something?
    – Narek
    Aug 20, 2015 at 6:53
  • Actually, yes. @Jordão has the answer I would prefer, based on the details we have in the question. That answer plays to the strategy pattern's strengths. If we went with the approach in this answer, I would want to have StrategyParameter contain all the possible params, just as a DTO. Some implementations of the strategy could ignore them. In some cases, that is the best approach. Context is king for these kind of issues.
    – tallseth
    Aug 21, 2015 at 13:59
1

As long as the signature is defined on the interface clearly, it still complies with the Strategy pattern.

The patterns as written are the absolute most simple form that still exhibits the behaviour expected, so you can embellish them as long as you keep the original intent. That of course is assuming you want to follow the pattern. There's no point using a pattern if it doesn't fit, or just because it's there, but in your case I think you're fine.

0

extending on the above answer provided by peakit - you can use abstraction. I am using peakit's code here -

Interface MyStrategy { abstract void myStrategyMethod(StrategyParameter parameter); }

class MyNormalStrategy extends MyStrategy { public override void myStrategyMethod(StrategyParameter parameter) { //implement the logic here } }

class MySpecializedStrategy extends MyStrategy { public override void myStrategyMethod(StrategyParameter parameter, ExtraStrategyParameter extraParameter) { //implement the logic here } }

If i understand your question correctly you wanted to pass an extra parameter to certain algorithms right ? Please let me know if this is what you were looking for ?

0

If you look into the Design patterns book, it isn't wrong per se that some SimpleStrategy exists that uses less or none of the passed parameters, or that the parameters are a one-size-fits-all/least-common-multiplier. The design choice here is whether this hurts you in terms of extra processing that ends up not being used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.