25% developed

Strategy

From Wikibooks, open books for an open world
Jump to navigation Jump to search

State Computer Science Design Patterns
Strategy
Template method

Scope

Object

Purpose

Behavioral

Intent

Define a family of algorithms, encapsulate each one, and make them interchangeable to let clients and algorithms vary independently from the clients using it.

Applicability

  • when an object should be configurable with one of several algorithms,
  • and all algorithms can be encapsulated,
  • and one interface covers all encapsulations

Structure

Consequences

  • + greater flexibility, reuse
  • + can change algorithms dynamically
  • - strategy creation & communication overhead
  • - inflexible Strategy interface

Implementation

  • exchanging information between a Strategy and its context
  • static strategy selection via templates

Related patterns

  • State, can activate several states, whereas a strategy can only activate one of the algorithms.
  • Flyweight, provides a shared object that can be used in multiple contexts simultaneously, whereas a strategy focuses on one context.
  • Decorator, changes the skin of an object, whereas a strategy changes the guts of an object.
  • Composite, is used in combination with a strategy to improve efficiency.

Description

Suppose that you work for a company that builds a strategy game. Let's assume that you've come up with the following hierarchy of classes. All characters are able to walk, and there is also a method to render them on screen. The superclass takes care of the implementation of walk() method, while each subclass provides its own implementation of display() since each character looks different.

A new requirement arrives that the characters need to fight, too. Simple job you say; just add a fight() method to Character superclass. But, wait a moment; what about Workers? They cannot fight!

Well, one could think that you could simply override fight() method in Worker subclass to just do nothing.

 class Worker {
      ....
      void fight() {
         // do nothing
      }
      ....
 }

But what if in the future there is a need for a Guard class that can fight but shouldn’t walk? We need a cleaner solution. What about taking out the fight and walk behaviors from the superclass to an interface? That way, only the characters that are supposed to walk should implement the Walkable interface and only those characters that are supposed to fight should implement the Fightable interface.

Well, this is another way to say for duplicate code. What if you need to make a small change to the fight behavior? You would need to modify all the classes. At this point we should put down three design principles to follow in our application development:

  1. Identify the aspects of your application that vary and separate them from what stays the same. Take what varies and “encapsulate” it so it won’t affect the rest of your code.
  2. Program to an interface not to an implementation.
  3. Favour composition over inheritance.

So, let's apply the 1st design principle. Pull out fight and walk behavior to different classes. And to apply the 2nd design principle as well, we have to pull out these behaviors to interfaces. Hence, we create a new WeaponBehavior interface to deal with fight behavior, and similarly a WalkBehavior interface to deal with walk behavior.

Characters’ behaviors live in separate classes that implement a particular behavior interface. That way, the Character classes don’t need to know any of the implementation details for their own behaviors. In addition, we no more rely on an implementation but on an interface. Other types of objects can use these behaviors, too, because they're not hidden inside our Character class. And we can add new behaviors without modifying any of the existing ones or touching our character classes. So now, all we have to do is have our Character class delegate all behavior information to the two behavior interfaces (so here comes the 3rd design principle). We do that by adding two instance variables to Character, weapon and walk.

 public abstract class Character {
  private WeaponBehavior weapon;
  private WalkBehavior walk;

  public void fight() {
     weapon.useWeapon(); // delegation of fight behavior
  }

  public void setWeapon(WeaponBehavior w) {
    weapon = w;
  }
  ...
  abstract void display();
 }

Each character object will set these variables polymorphically to reference the specific behavior type it would like at runtime.

 public class Knight extends Character {
  public Knight() {
    weapon = new SwordBehavior();
    walk = new GallopBehavior();
  }

  public void display() {
    ...
  }
 }

Think of these behaviors as families of algorithms. So, composition gives you a lot of flexibility. Not only does it let you encapsulate a family of algorithms into their own set of classes, but it also lets you change behavior at runtime as long as the object you are composing with, implements the correct behavior interface.

Examples

Clipboard

To do:
Find an example.


Cost

Think twice before implementing this pattern. You have to be sure your need is to frequently change an algorithm. You have to clearly anticipate the future, otherwise, this pattern will be more expensive than a basic implementation.

Creation

This pattern is expensive to create.

Maintenance

This pattern can be expensive to maintain. If the representation of a class often changes, you will have lots of refactoring.

Removal

This pattern is hard to remove too.

Advises

  • Use the strategy term to indicate the use of the pattern to the other developers.

Implementations

Implementation in ActionScript 3

The strategy pattern in ActionScript 3:

//invoked from application.initialize
private function init() : void
{
    var context:Context;

    context = new Context( new ConcreteStrategyA() );
    context.execute();

    context = new Context( new ConcreteStrategyB() );
    context.execute();

    context = new Context( new ConcreteStrategyC() );
    context.execute();
}

package org.wikipedia.patterns.strategy
{
    public interface IStrategy
    {
    function execute() : void ;
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyA implements IStrategy
    {
    public function execute():void
    {
         trace( "ConcreteStrategyA.execute(); invoked" );
    }
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyB implements IStrategy
    {
    public function execute():void
    {
         trace( "ConcreteStrategyB.execute(); invoked" );
    }
    }
}

package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyC implements IStrategy
    {
    public function execute():void
    {
         trace( "ConcreteStrategyC.execute(); invoked" );
    }
    }
}

package org.wikipedia.patterns.strategy
{
   public class Context
   {
    private var strategy:IStrategy;
       
    public function Context(strategy:IStrategy)
    {
         this.strategy = strategy;
    }
       
    public function execute() : void
    {  
             strategy.execute();
    }
    }
}
Implementation in C

A struct in C can be used to define a class, and the strategy can be set using a function pointer. The following mirrors the Python example, and uses C99 features:

#include <stdio.h>

void print_sum(int n, int *array) {
    int total = 0;
    for (int i = 0; i < n; i++)
        total += array[i];
    printf("%d", total);
}

void print_array(int n, int *array) {
    for (int i = 0; i < n; i++)
        printf("%d ", array[i]);
}

typedef struct {
    void (*submit_func)(int n, int *array);  // function pointer
    char *label;                             // instance label
} Button;

int main(void) {
    // Create two instances with different strategies
    Button button1 = { print_sum, "Add 'em" };
    Button button2 = { print_array, "List 'em" };

    int n = 10;
    int numbers[n];
    for (int i = 0; i < n; i++)
        numbers[i] = i;

    button1.submit_func(n, numbers);
    button2.submit_func(n, numbers);
 
    return 0;
}
Implementation in C++

The strategy pattern in C++ is similar to Java, but does not require dynamic allocation of objects.

#include <iostream>

class Strategy
{
public:
     virtual int execute (int a, int b) = 0; // execute() is a so-called pure virtual function
                                             // as a consequence, Strategy is a so-called abstract class
};
 
class ConcreteStrategyAdd:public Strategy
{
public:
    int execute(int a, int b)
    {
        std::cout << "Called ConcreteStrategyAdd's execute()\n";
        return a + b;
    }
};
 
class ConcreteStrategySubstract:public Strategy
{
public:
    int execute(int a, int b)
    {
        std::cout << "Called ConcreteStrategySubstract's execute()\n";
        return a - b;
    }
};
 
class ConcreteStrategyMultiply:public Strategy
{
public:
    int execute(int a, int b)
    {
        std::cout << "Called ConcreteStrategyMultiply's execute()\n";
        return a * b;
    }
};

class Context
{
private:
    Strategy* pStrategy;
 
public:

    Context (Strategy& strategy)
        : pStrategy(&strategy)
    {
    }

    void SetStrategy(Strategy& strategy)
    {
        pStrategy = &strategy;
    }
 
    int executeStrategy(int a, int b)
    {
        return pStrategy->execute(a,b);
    }
};
 
int main()
{
    ConcreteStrategyAdd       concreteStrategyAdd;
    ConcreteStrategySubstract concreteStrategySubstract;
    ConcreteStrategyMultiply  concreteStrategyMultiply;

    Context context(concreteStrategyAdd);
    int resultA = context.executeStrategy(3,4);
 
    context.SetStrategy(concreteStrategySubstract);
    int resultB = context.executeStrategy(3,4);
 
    context.SetStrategy(concreteStrategyMultiply);
    int resultC = context.executeStrategy(3,4);
 
    std::cout << "resultA: " << resultA << "\tresultB: " << resultB << "\tresultC: " << resultC << "\n";
}
Implementation in C#
public class StrategyPatternWiki
{
    public static void Main(String[] args)
    {
        // Prepare strategies
        var normalStrategy    = new NormalStrategy();
        var happyHourStrategy = new HappyHourStrategy();

        var firstCustomer = new CustomerBill(normalStrategy);

        // Normal billing
        firstCustomer.Add(1.0, 1);

        // Start Happy Hour
        firstCustomer.Strategy = happyHourStrategy;
        firstCustomer.Add(1.0, 2);

        // New Customer
        var secondCustomer = new CustomerBill(happyHourStrategy);
        secondCustomer.Add(0.8, 1);
        // The Customer pays
        firstCustomer.Print();

        // End Happy Hour
        secondCustomer.Strategy = normalStrategy;
        secondCustomer.Add(1.3, 2);
        secondCustomer.Add(2.5, 1);
        secondCustomer.Print();
    }
}

// CustomerBill as class name since it narrowly pertains to a customer's bill
class CustomerBill
{
    private IList<double> drinks;

    // Get/Set Strategy
    public IBillingStrategy Strategy { get; set; }

    public CustomerBill(IBillingStrategy strategy)
    {
        this.drinks = new List<double>();
        this.Strategy = strategy;
    }

    public void Add(double price, int quantity)
    {
        this.drinks.Add(this.Strategy.GetActPrice(price) * quantity);
    }

    // Payment of bill
    public void Print()
    {
        double sum = 0;
        foreach (var drinkCost in this.drinks)
        {
            sum += drinkCost;
        }
        Console.WriteLine($"Total due: {sum}.");
        this.drinks.Clear();
    }
}

interface IBillingStrategy
{
    double GetActPrice(double rawPrice);
}

// Normal billing strategy (unchanged price)
class NormalStrategy : IBillingStrategy
{
    public double GetActPrice(double rawPrice) => rawPrice;
}

// Strategy for Happy hour (50% discount)
class HappyHourStrategy : IBillingStrategy
{
    public double GetActPrice(double rawPrice) => rawPrice * 0.5;
}

Another Example:

Delegates in C# follow the strategy pattern, where the delegate definition defines the strategy interface and the delegate instance represents the concrete strategy. .NET 3.5 defines the Func<,> delegate which can be used to quickly implement the strategy pattern as shown in the example below. Note the 3 different methods for defining a delegate instance.

using System;
using System.Linq;
class Program
{
    static void Main(string[] args)
    {
        var context = new Context<int>();

        // Delegate
        Func<int, int, int> concreteStrategy1 = PerformLogicalBitwiseOr;

        // Anonymous Delegate
        Func<int, int, int> concreteStrategy2 = delegate(int op1, int op2) { return op1 & op2; };

        // Lambda Expressions
        Func<int, int, int> concreteStrategy3 = (op1, op2) => op1 >> op2;
        Func<int, int, int> concreteStrategy4 = (op1, op2) => op1 << op2;

        context.Strategy = concreteStrategy1;
        var result1 = context.Execute(8, 9);
        context.Strategy = concreteStrategy2;
        var result2 = context.Execute(8, 9);
        context.Strategy = concreteStrategy3;
        var result3 = context.Execute(8, 1);
        context.Strategy = concreteStrategy4;
        var result4 = context.Execute(8, 1);
    }

    static int PerformLogicalBitwiseOr(int op1, int op2)
    {
        return op1 | op2;
    }

    class Context<T>
    {
        public Func<T, T, T> Strategy { get; set; }

        public T Execute(T operand1, T operand2)
        {
            return this.Strategy != null
                ? this.Strategy(operand1, operand2)
                : default(T);
        }
    }
}

Using interfaces

using System;

namespace Wikipedia.Patterns.Strategy
{
  // The strategy we will implement will be
  // to advise on investments.
  interface IHasInvestmentStrategy
  {
    long CalculateInvestment();
  }
  // Here we have one way to go about it.
  class FollowTheMoon : IHasInvestmentStrategy
  {
    protected virtual int MoonPhase { get; set; }
    protected virtual int AstrologicalSign { get; set; }
    public FollowTheMoon(int moonPhase, int yourSign)
    {
      MoonPhase = moonPhase;
      AstrologicalSign = yourSign;
    }
    public long CalculateInvestment()
    {
      if (MoonPhase == AstrologicalSign)
        return 1000;
      else
        return 100 * (MoonPhase % DateTime.Today.Day);
    }
  }
  // And here we have another.
  // Note that each strategy may have its own dependencies.
  // The EverythingYouOwn strategy needs a bank account.
  class EverythingYouOwn : IHasInvestmentStrategy
  {
    protected virtual OtherLib.IBankAccessor Accounts { get; set; }
    public EverythingYouOwn(OtherLib.IBankAccessor accounts)
    {
      Accounts = accounts;
    }
    public long CalculateInvestment()
    {
      return Accounts.GetAccountBalancesTotal();
    }
  }
  // The InvestmentManager is where we want to be able to
  // change strategies. This is the Context.
  class InvestmentManager
  {
    public IHasInvestmentStrategy Strategy { get; set; }
    public InvestmentManager(IHasInvestmentStrategy strategy)
    {
      Strategy = strategy;
    }
    public void Report()
    {
      // Our investment is determined by the current strategy.
      var investment = Strategy.CalculateInvestment();
      Console.WriteLine("You should invest {0} dollars!",
        investment);
    }
  }
  class Program
  {
    static void Main()
    {
      // Define some of the strategies we will use.
      var strategyA = new FollowTheMoon( 8, 8 );
      var strategyB = new EverythingYouOwn(
        OtherLib.BankAccountManager.MyAccount);
      // Our investment manager
      var manager = new InvestmentManager(strategyA);
      manager.Report();
      // You should invest 1000 dollars!
      manager.Strategy = strategyB;
      manager.Report();
      // You should invest 13521500000000 dollars!
    }
  }
}
Implementation in Common Lisp

An example in Common Lisp: Using strategy classes:

(defclass context ()
  ((strategy :initarg :strategy :accessor strategy)))

(defmethod execute ((c context))
  (execute (slot-value c 'strategy)))

(defclass strategy-a () ())

(defmethod execute ((s strategy-a))
  (print "Doing the task the normal way"))

(defclass strategy-b () ())

(defmethod execute ((s strategy-b))
  (print "Doing the task alternatively"))

(execute (make-instance 'context
                        :strategy (make-instance 'strategy-a)))

In Common Lisp using first class functions:

(defclass context ()
  ((strategy :initarg :strategy :accessor strategy)))

(defmethod execute ((c context))
  (funcall (slot-value c 'strategy)))

(let ((a (make-instance 'context
                        :strategy (lambda ()
                                    (print "Doing the task the normal way")))))
  (execute a))

(let ((b (make-instance 'context
                        :strategy (lambda ()
                                    (print "Doing the task alternatively")))))
  (execute b))
Implementation in Falcon

Similar to Python and Scala, Falcon supports first-class functions. The following implements the basic functionality seen in the Python example.

  /*#
    @brief A very basic button widget
  */
  class Button( label, submit_func )
    label = label
    on_submit = submit_func
  end
 
  // Create two instances with different strategies ...
  // ... and different ways to express inline functions
  button1 = Button( "Add 'em",
      function(nums)
         n = 0
         for val in nums: n+= val
         return n
       end )
  button2 = Button( "Join 'em", { nums => " ".merge( [].comp(nums) ) } )
 
  // Test each button
  numbers = [1: 10]  
  printl(button1.on_submit(numbers))   // displays "45"
  printl(button2.on_submit(numbers))   // displays "1 2 3 4 5 6 7 8 9"
Implementation in Fortran

Fortran 2003 adds procedure pointers, abstract interfaces and also first-class functions. The following mirrors the Python example.

module m_strategy_pattern
implicit none

abstract interface
    !! A generic interface to a subroutine accepting array of integers
    subroutine generic_function(numbers)
        integer, dimension(:), intent(in) :: numbers
    end subroutine
end interface

type :: Button
    character(len=20) :: label
    procedure(generic_function), pointer, nopass :: on_submit
contains
    procedure :: init
end type Button

contains

    subroutine init(self, func, label)
        class(Button), intent(inout) :: self
        procedure(generic_function) :: func
        character(len=*) :: label
        self%on_submit => func      !! Procedure pointer
        self%label = label
    end subroutine init

    subroutine summation(array)
        integer, dimension(:), intent(in) :: array
        integer :: total
        total = sum(array)
        write(*,*) total
    end subroutine summation

    subroutine join(array)
        integer, dimension(:), intent(in) :: array
        write(*,*) array        !! Just write out the whole array
    end subroutine join

end module m_strategy_pattern

!! The following program demonstrates the usage of the module
program test_strategy
use m_strategy_pattern
implicit none

    type(Button) :: button1, button2
    integer :: i

    call button1%init(summation, "Add them")
    call button2%init(join, "Join them")

    call button1%on_submit([(i, i=1,10)])   !! Displays 55
    call button2%on_submit([(i, i=1,10)])   !! Prints out the array

end program test_strategy
Implementation in Groovy

This Groovy example is a basic port of the Ruby using blocks example. In place of Ruby's blocks, the example uses Groovy's closure support.

class Context {
  def strategy

  Context(strategy) {
    this.strategy = strategy
  }
 
  def execute() {
    strategy()
  }
}

def a = new Context({ println 'Style A' })
a.execute() // => Style A
def b = new Context({ println 'Style B' })
b.execute() // => Style B
def c = new Context({ println 'Style C' })
c.execute() // => Style C
Implementation in "classical" Java

An example in Java:

/** The classes that implement a concrete strategy should implement this.
* The Context class uses this to call the concrete strategy. */
interface Strategy {
    int execute(int a, int b);
}
/** Implements the algorithm using the strategy interface */
class Add implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Add's execute()");
        return a + b;  // Do an addition with a and b
    }
}
class Subtract implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Subtract's execute()");
        return a - b;  // Do a subtraction with a and b
    }
}
class Multiply implements Strategy {
    public int execute(int a, int b) {
        System.out.println("Called Multiply's execute()");
        return a * b;   // Do a multiplication with a and b
    }    
}
/** Configured with a ConcreteStrategy object and maintains a reference to a Strategy object */
class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b) {
        return this.strategy.execute(a, b);
    }
}
/** Tests the pattern */
class StrategyExample {
    public static void main(String[] args) {
        Context context;

        // Three contexts following different strategies
        context = new Context(new Add());
        int resultA = context.executeStrategy(3, 4);

        context = new Context(new Subtract());
        int resultB = context.executeStrategy(3, 4);

        context = new Context(new Multiply());
        int resultC = context.executeStrategy(3, 4);
     
        System.out.println("Result A: " + resultA );
        System.out.println("Result B: " + resultB );
        System.out.println("Result C: " + resultC );
    }
}
Implementation in Java 8

An example in Java:

/** Imports a type of lambdas taking two arguments of the same type T and returning one argument of same type T */
import java.util.function.BinaryOperator;

/** Implements and assigns to variables the lambdas to be used later in configuring Context.
*   FunctionalUtils is just a convenience class, as the code of a lambda
*   might be passed directly to Context constructor, as for ResultD below, in main().
*/
class FunctionalUtils {
	static final BinaryOperator<Integer> add = (final Integer a, final Integer b) -> {
		System.out.println("Called add's apply().");
		return a + b;
	};

	static final BinaryOperator<Integer> subtract = (final Integer a, final Integer b) -> {
		System.out.println("Called subtract's apply().");
		return a - b;
	};

	static final BinaryOperator<Integer> multiply = (final Integer a, final Integer b) -> {
		System.out.println("Called multiply's apply().");
		return a * b;
	};
}
/** Configured with a lambda and maintains a reference to a lambda */
class Context {
	/** a variable referencing a lambda taking two Integer arguments and returning an Integer: */
	private final BinaryOperator<Integer> strategy;
    	
	public Context(final BinaryOperator<Integer> lambda) {
		strategy = lambda;
	}

	public int executeStrategy(final int a, final int b) {
		return strategy.apply(a, b);
	}
}
/** Tests the pattern */
public class StrategyExample {

	public static void main(String[] args) {
		Context context;

		context = new Context(FunctionalUtils.add);
		final int resultA = context.executeStrategy(3,4);

		context = new Context(FunctionalUtils.subtract);
		final int resultB = context.executeStrategy(3, 4);

		context = new Context(FunctionalUtils.multiply);
		final int resultC = context.executeStrategy(3, 4);

		context = new Context((final Integer a, final Integer b) -> a * b + 1);
		final int resultD = context.executeStrategy(3,4);

		System.out.println("Result A: " + resultA );
		System.out.println("Result B: " + resultB );
		System.out.println("Result C: " + resultC );
		System.out.println("Result D: " + resultD );
	}
}
Implementation in JavaScript

Similar to Python and Scala, JavaScript supports first-class functions. The following implements the basic functionality seen in the Python example.

var Button = function(submit_func, label) {
    this.label = label;
    this.on_submit = submit_func;
};

var numbers = [1,2,3,4,5,6,7,8,9];
var sum = function(n) {
    var sum = 0;
    for ( var a in n ) {
        sum = sum + n[a];
    }
    return sum;
};

var a = new Button(sum, "Add numbers");
var b = new Button(function(numbers) {
    return numbers.join(',');
}, "Print numbers");

a.on_submit(numbers);
b.on_submit(numbers);
Implementation in Perl

Perl has first-class functions, so as with Python, JavaScript and Scala, this pattern can be implemented without defining explicit subclasses and interfaces:

sort { lc($a) cmp lc($b) } @items

The strategy pattern can be formally implemented with Moose:

package Strategy;
use Moose::Role;
requires 'execute';

package FirstStrategy;
use Moose;
with 'Strategy';

sub execute {
    print "Called FirstStrategy->execute()\n";
}

package SecondStrategy;
use Moose;
with 'Strategy';

sub execute {
    print "Called SecondStrategy->execute()\n";
}

package ThirdStrategy;
use Moose;
with 'Strategy';

sub execute {
    print "Called ThirdStrategy->execute()\n";
}

package Context;
use Moose;

has 'strategy' => (
    is => 'rw',
    does => 'Strategy',
    handles => [ 'execute' ],  # automatic delegation
);

package StrategyExample;
use Moose;

# Moose's constructor
sub BUILD {
    my $context;

    $context = Context->new(strategy => 'FirstStrategy');
    $context->execute;

    $context = Context->new(strategy => 'SecondStrategy');
    $context->execute;

    $context = Context->new(strategy => 'ThirdStrategy');
    $context->execute;
}

package main;

StrategyExample->new;
Implementation in PHP

The strategy pattern in PHP:

<?php
interface IStrategy {
    public function execute();
}

class Context {
    private $strategy;

    public function __construct(IStrategy $strategy) {
        $this->strategy = $strategy;
    }

    public function execute() {
        $this->strategy->execute();
    }
}

class ConcreteStrategyA implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyA execute method\n";
    }
}

class ConcreteStrategyB implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyB execute method\n";
    }
}

class ConcreteStrategyC implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyC execute method\n";
    }
}

class StrategyExample {
    public function __construct() {
        $context = new Context(new ConcreteStrategyA());
        $context->execute();

        $context = new Context(new ConcreteStrategyB());
        $context->execute();

        $context = new Context(new ConcreteStrategyC());
        $context->execute();
    }
}

new StrategyExample();
?>
Implementation in PowerShell

PowerShell has first-class functions called ScriptBlocks, so the pattern can be modeled like Python, passing the function directly to the context instead of defining a class.

Function Context ([scriptblock]$script:strategy){
    New-Module -Name Context -AsCustomObject {
        Function Execute { & $strategy }
    }
}

$a = Context {'Style A'}
$a.Execute()

(Context {'Style B'}).Execute()

$c = Context {'Style C'}
$c.Execute()

An alternative to using New-Module

Function Context ([scriptblock]$strategy){
    { & $strategy }.GetNewClosure()
}

$a = Context {'Style A'}
$a.Invoke()

& (Context {'Style B'})

$c = Context {'Style C'}
& $c
Implementation in Python

The following example is equivalent to the C# example 1 above, but in Python.

import abc


class Bill:
    def __init__(self, billing_strategy: "BillingStrategy"):
        self.drinks: list[float] = []
        self.billing_strategy = billing_strategy

    def add(self, price: float, quantity: int) -> None:
        self.drinks.append(self.billing_strategy.get_act_price(price * quantity))

    def __str__(self) -> str:
        return f{sum(self.drinks)}"


class BillingStrategy(abc.ABC):
    @abc.abstractmethod
    def get_act_price(self, raw_price: float) -> float:
        raise NotImplementedError


class NormalStrategy(BillingStrategy):
    def get_act_price(self, raw_price: float) -> float:
        return raw_price


class HappyHourStrategy(BillingStrategy):
    def get_act_price(self, raw_price: float) -> float:
        return raw_price * 0.5


def main() -> None:
    normal_strategy = NormalStrategy()
    happy_hour_strategy = HappyHourStrategy()

    customer_1 = Bill(normal_strategy)
    customer_2 = Bill(normal_strategy)

    # Normal billing
    customer_1.add(2.50, 3)
    customer_1.add(2.50, 2)

    # Start happy hour
    customer_1.billing_strategy = happy_hour_strategy
    customer_2.billing_strategy = happy_hour_strategy
    customer_1.add(3.40, 6)
    customer_2.add(3.10, 2)

    # End happy hour
    customer_1.billing_strategy = normal_strategy
    customer_2.billing_strategy = normal_strategy
    customer_1.add(3.10, 6)
    customer_2.add(3.10, 2)

    # Print the bills;
    print(customer_1)
    print(customer_2)

if __name__ == "__main__":
    main()

Second example in Python:

class Strategy:
    def execute(self, a, b):
        pass

class Add(Strategy):
    def execute(self, a, b):
        return a + b

class Subtract(Strategy):
    def execute(self, a, b):
        return a - b

class Multiply(Strategy):
    def execute(self, a, b):
        return a * b

class Context:
    def __init__(self, strategy):
        self.strategy = strategy

    def execute(self, a, b):
        return self.strategy.execute(a, b)

if __name__ == "__main__":
    context = None

    context = Context(Add())
    print "Add Strategy %d" % context.execute(10, 5)

    context = Context(Subtract())
    print "Subtract Strategy %d" % context.execute(10, 5)

    context = Context(Multiply())
    print "Multiply Strategy %d" % context.execute(10, 5)

Another example in Python: Python has first-class functions, so the pattern can be used simply by passing the function directly to the context instead of defining a class with a method containing the function. One loses information because the interface of the strategy is not made explicit, however, by simplifying the pattern in this manner.

Here's an example you might encounter in GUI programming, using a callback function:

class Button:
    """A very basic button widget."""
    def __init__(self, submit_func, label):
        self.on_submit = submit_func   # Set the strategy function directly
        self.label = label

# Create two instances with different strategies
button1 = Button(sum, "Add 'em")
button2 = Button(lambda nums: " ".join(map(str, nums)), "Join 'em")

# Test each button
numbers = range(1, 10)   # A list of numbers 1 through 9
print button1.on_submit(numbers)   # displays "45"
print button2.on_submit(numbers)   # displays "1 2 3 4 5 6 7 8 9"
Implementation in Ruby

An example in Ruby:

class Context
  def initialize(strategy)
    extend(strategy)
  end
end

module StrategyA
  def execute
     puts 'Doing the task the normal way'
  end
end

module StrategyB
  def execute
     puts 'Doing the task alternatively'
  end
end

module StrategyC
  def execute
     puts 'Doing the task even more alternatively'
  end
end

a = Context.new(StrategyA)
a.execute #=> Doing the task the normal way

b = Context.new(StrategyB)
b.execute #=> Doing the task alternatively

a.execute #=> Doing the task the normal way

c = Context.new(StrategyC)
c.execute #=> Doing the task even more alternatively

Using blocks

The previous ruby example uses typical OO features, but the same effect can be accomplished with ruby's blocks in much less code.

class Context
  def initialize(&strategy)
    @strategy = strategy
  end

  def execute
    @strategy.call
  end
end

a = Context.new { puts 'Doing the task the normal way' }
a.execute #=> Doing the task the normal way

b = Context.new { puts 'Doing the task alternatively' }
b.execute #=> Doing the task alternatively
 
c = Context.new { puts 'Doing the task even more alternatively' }
c.execute #=> Doing the task even more alternatively
Implementation in Scala

Like Python, Scala also supports first-class functions. The following implements the basic functionality shown in the Python example.

  // A very basic button widget.
  class Button[T](val label: String, val onSubmit: Range => T)
 
  val button1 = new Button("Add", _ reduceLeft (_ + _))
  val button2 = new Button("Join", _ mkString " ")
 
  // Test each button
  val numbers = 1 to 9  // A list of numbers 1 through 9
  println(button1 onSubmit numbers) // displays 45
  println(button2 onSubmit numbers) // displays 1 2 3 4 5 6 7 8 9


Clipboard

To do:
Add more illustrations.


State Computer Science Design Patterns
Strategy
Template method


You have questions about this page?
Ask it here:


Create a new page on this book: