Search code examples
oopdesign-patternsobserver-patternstrategy-pattern

What is the strategy pattern with reversed flow of control?


In my understanding the strategy pattern is used to make behaviour interchangable. This involves that the responsibility of the strategy is defined in an interface, to which the client may then delegate calls. E.g. suppose a value can be obtained in different ways, the interface would have a method "getValue()".

My question concerns the case where the flow of control is opposite. For example if the concrete strategy initiates the request "onValueChanged()" on the client (suppose it has a reference to the client or a callback interface).

Is this still considered a strategy pattern?

Update - added the following source code example:

interface DataSupplierCb
{
  void onValueChanged(int a);
}

interface DataSupplier
{
  void check();
}

// NOTE 1: Data supplier knows how the get the value
class ConcreteDataSupplier : public DataSupplier
{
  void check()
  {        
    myDataSupplierCb.onValueChanged(47);
  }
}

class Client : public DataSupplierCb
{
  void onValueChanged(int a)
  {
    // NOTE 2: Client knows what to do with the value
  }

  void changeDataSupplier(int i)
  {
    if (i == 1)
    {
      myCurrentDataSupplier = new ConcreteDataSupplier(this);
    }
  }
}

Solution

  • If the intent of the DataSupplier interface to allow your Client to swap in, and delegate to, different concrete data-fetching implementations then yes it can be considered a strategy. Your Client is shielded from the details (aka strategy) used to fetch the value as expected in the use of the Strategy pattern. And the fact that the Client reference is passed to the Strategy is fine and common:

    (From the GoF)

    "Strategy and Context interact to implement the chosen algorithm. A context may pass all data required by the algorithm to the strategy when the algorithm is called. Alternatively, the context can pass itself as an argument to Strategy operations. That lets the strategy call back on the context as required."

    The Context for you is Client.

    Now that all being said, rare is a solution that uses only one pattern. Your notification does seem to use the Observer pattern as another poster commented, and that is fine.

    What I don't like about what you have implemented though is that your Strategy is a pure interface. Not always a bad thing, but in this case, with that notification callback, an interface does not provide a guarantee that the notifictaion callback is going to happen. Interfaces only guarantee the method signatures. I would recommend using the Template pattern in a base class to derrive the strategies from.

    abstract class DataSupplier
    {
    
       protected ClientInterface _client;
    
       // ctor takes in context
       public DataSupplier(ClientInterface client)
       {
          _client - client;
       }
    
       public void check()
       {
          int priorValue = 46;
    
          int newValue = OnGetValue(); 
    
          if (priorValue != newValue)
             _client.onValueChanged(newValue)
    
       }
    
       protected abstract int OnCheck();
    
    }
    

    And then:

    class ConcreteDataSupplier : DataSupplier
    {
    
       // Check, and notification, are handled by the base.  We only need
       // to implement the actually data fetching
    
       int OnGetValue()
       {        
          return someValue;
       }
    }
    

    With this approach, I know the notification will be handled. I don't need to worry about an implementor forgetting it in a new strategy later.