Strategy

Design patterns / Behavioral patterns
image

type
  //the algorithm is swappable
  IStrategy = interface
    function DoOperation(
      A, B: Integer): Integer;
  end;

  TAddStrategy = class(TInterfacedObject,
    IStrategy)
    function DoOperation(
      A, B: Integer): Integer;
  end;

  TSubtractStrategy = class(
    TInterfacedObject, IStrategy)
    function DoOperation(
      A, B: Integer): Integer;
  end;

  //context holds a strategy and
  //only calls it
  TCalc = class
  private
    FStrategy: IStrategy;
  public
    function Execute(
      A, B: Integer): Integer;
    procedure SetStrategy(
      const Strategy: IStrategy);
  end;

function TAddStrategy.DoOperation(
  A, B: Integer): Integer;
begin
  Result := A + B;
end;

function TSubtractStrategy.DoOperation(
  A, B: Integer): Integer;
begin
  Result := A - B;
end;

function TCalc.Execute(
  A, B: Integer): Integer;
begin
  if FStrategy = nil then
    Result := 0
  else
    Result := FStrategy.DoOperation(A, B);
end;

procedure TCalc.SetStrategy(
  const Strategy: IStrategy);
begin
  FStrategy := Strategy;
end;

var
  Calc: TCalc;
begin
  Calc := TCalc.Create;
  WriteLn('result1 is ', Calc.Execute(5, 3));
  //result1 is 0

  Calc.SetStrategy(TAddStrategy.Create);
  WriteLn('result2 is ', Calc.Execute(5, 3));
  //result2 is 8

  Calc.SetStrategy(TSubtractStrategy.Create);
  WriteLn('result3 is ', Calc.Execute(5, 3));
  //result3 is 2
end.


Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Read more

The problem. A shop calculates the cost of delivery: by weight, by distance or at a fixed price. If one method holds all the ways in a chain of conditions, it grows with every new way. A change to one way can break the others, and no way can be tested alone.

The idea. Each way of doing the job becomes a separate object, called a strategy. All strategies have the same shape: the same inputs and the same kind of result. The object that needs the job done, called the context, holds one strategy and calls it. It does not know which strategy it holds. The client code chooses the strategy and can replace it at any time.

How to read the example. Each concrete strategy is one algorithm, and all of them take the same inputs. The client code chooses a strategy. The code that uses the strategy only calls it and does not know which one it received. In most examples the same two numbers give a different result after each change of strategy. Most of them also give an answer for the case with no strategy. In some languages a strategy is simply a function.

When to use it. Use Strategy when there are several ways to do one job, and the choice depends on the user, the data or the settings. Do not use it for one algorithm that will not change. Strategy looks like State, but the difference is who makes the choice. Here the client code chooses the algorithm from outside, and the strategies know nothing about each other. In State, the object moves from state to state by itself.

A common mistake. Making the context check which strategy it holds. The conditions then return, and the pattern loses its purpose. The context must only call the strategy.