Wednesday, 1 January 2020

Design Pattern - Strategy

Strategy Pattern

G.O.F. book says following about Strategy Pattern :

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

Applicability Use the strategy pattern when :

  • many related classes differ only in their behaviour. Strategies provide a way to configure a class with one of many behaviours.
  • you need different variants of an algorithm ... space/time trade offs ...
  • an algorithm uses data that the clients shouldnt know about ...
  • a class defines many behaviours and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches in their own Strategy class.

strategy_pattern.png

In [9]:
# inspired (shamelessly copied) from : 
# https://refactoring.guru/design-patterns/strategy/python/example#lang-features

from abc import ABC, abstractmethod
from typing import List

# interface common to all strategies used by context        
class Strategy(object):
    @abstractmethod
    def do_algorithm(self, input_list : List) -> List:
        pass

# context which uses the strategy interface
class Context(ABC):
    def __init__(self, strategy: Strategy) -> None:
        self._strategy = strategy
    
    @property
    def strategy(self) -> Strategy:
        return self._strategy
    
    @strategy.setter
    def strategy(self, strategy: Strategy) -> None:
        self._strategy = strategy
        
    def do_some_business(self) -> None:
        print('Context : Dont know which strategy it is !')
        result = self._strategy.do_algorithm([3,1,2,4])
        print('Result :', [ x for x in result])

    
# some concrete implementations of the strategy used by context
class ConcreteStrategySort(Strategy):
    def do_algorithm(self, input_list: List) -> List:
        return sorted(input_list)
    
class ConcreteStrategyReverseSort(Strategy):
    def do_algorithm(self, input_list: List) -> List:
        return reversed(sorted(input_list))

# client code
if __name__ == '__main__':
    context_with_strategy_sort = Context(ConcreteStrategySort())
    print('Client : Strategy is set to ConcreteStrategySort')
    context_with_strategy_sort.do_some_business()
    
    print()
    
    context_with_stratecy_reverse_sort = Context(ConcreteStrategyReverseSort())
    print('Client : Strategy is set to ConcreteStrategyReverseSort')
    context_with_stratecy_reverse_sort.do_some_business()
Client : Strategy is set to ConcreteStrategySort
Context : Dont know which strategy it is !
Result : [1, 2, 3, 4]

Client : Strategy is set to ConcreteStrategyReverseSort
Context : Dont know which strategy it is !
Result : [4, 3, 2, 1]
In [ ]:
 

No comments:

Post a Comment