Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In the strategy pattern can the strategy take the Context as parameter


Feedback summary

I will now close this thead (I think there will be no more feedback) and try to summarize what I understood

  1. using the "Context" as a parameter for my strategy introduces a tight coupling that should be avoided and also could force me to expose properties that should perhaps remain hidden in the class.
  2. To minimize coupling, it would be better to provide the needed values or at least to use an interface instead of a concrete type to the strategy.

I'm trying to get a clear overview of the strategy pattern and I'm asking myself if it is a good or bad design to have the strategy depends on the context.

Let's take the following classical implementation

//The strategy
interface IStrategy  
{  
  void Execute();  
}  

class ConcreteStrategyA : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
  }
}

class ConcreteStrategyB : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
  }
}

//The context
class Context
{
  IStrategy strategy;

  // Constructor
  public Context(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void UpdateContext(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void Execute()
  {
    strategy.Execute();
  }
}

All examples I have seen have pretty simple strategies that take basic arguments (integers for example). What I would like to know is if there is something wrong if the strategy uses the Context to do the work.

It would give something like

//The strategy
interface IStrategy  
{  
  void Execute(Context arg);  
}  

and the invocation would give

//The context
class Context
{
  ....

  public void Execute()
  {
    strategy.Execute(this);
  }
}

Is this "coupling" to be avoided? Is it ok?

like image 846
FrenchData Avatar asked Jan 09 '10 17:01

FrenchData


1 Answers

One issue I see with your approach is that there would a tight coupling between the concrete Context class and the instances of the Strategy classes. This would imply that the Strategy classes can be used only with the Context class . One way to circumvent this is that to make your strategy classes dependent (or use) an interface that the 'Context' class would implement.

EDIT Also when the Strategy classes have an instance of Context class, these classes have to get the explicitly data from the Context class. This would mean adding getters (as necessary) in the Context class for strategy classes to get the data they need. But adding getters is not necessarily a good OO practice as more getters pose the risk of breaking the encapsulation.

An alternative you can think of is to not pass the reference (this) of Context class to the method(s) in strategy class but to pass only the needed data to the Strategy class.

For example if the Context class is something like this: (the code is in Java)

Context {
   IStrategy strategy;
   List<Integer> scores;

   public Context(IStrategy strategy)
   {
        this.strategy = strategy;
        scores = new ArrayList<Integer>
   }

   public print() {
       strategy.sort(scores);
   }
}

public interface IStrategy<Integer> {
    public void sort(List<Integer> l);
}

In the above code the Strategy class operates on a generic Integer list and is not particularly bound to be used with the Context class. Also taking further one can use a generic method while defining the Strategy class so that sort method is not just applicable to Integers but also to generic types.

like image 66
sateesh Avatar answered Nov 28 '22 05:11

sateesh