diff --git a/behavioral/strategy/concrete_strategies.py b/behavioral/strategy/concrete_strategies.py new file mode 100644 index 0000000..18e2b3d --- /dev/null +++ b/behavioral/strategy/concrete_strategies.py @@ -0,0 +1,15 @@ +""" +Concrete Strategies implement the algorithm while following the base Strategy interface. The interface makes them +interchangeable in the Context. +""" +from behavioral.strategy.strategy import Strategy + + +class ConcreteStrategyA(Strategy): + def do_algorithm(self, data: list) -> list: + return sorted(data) + + +class ConcreteStrategyB(Strategy): + def do_algorithm(self, data: list) -> list: + return reversed(sorted(data)) diff --git a/behavioral/strategy/context.py b/behavioral/strategy/context.py new file mode 100644 index 0000000..2a077e3 --- /dev/null +++ b/behavioral/strategy/context.py @@ -0,0 +1,40 @@ +from behavioral.strategy.strategy import Strategy + + +class Context: + """ + The Context defines the interface of interest to clients. + """ + + def __init__(self, strategy: Strategy): + """ + Usually, the Context accepts a strategy through the constructor, but also provides a setter to change it at + runtime. + """ + self._strategy = strategy + + @property + def strategy(self): + """ + The Context maintains a reference to one of the Strategy objects. The + Context does not know the concrete class of a strategy. It should work + with all strategies via the Strategy interface. + """ + return self._strategy + + @strategy.setter + def strategy(self, strategy: Strategy): + """ + Usually, the Context allows replacing a Strategy object at runtime. + """ + self._strategy = strategy + + def do_some_business_logic(self) -> None: + """ + The Context delegates some work to the Strategy object instead of implementing multiple versions of the + algorithm on its own. + """ + + print("Context: Sorting data using the strategy (not sure how it'll do it)") + result = self._strategy.do_algorithm(["a", "b", "c", "d", "e"]) + print(",".join(result)) diff --git a/behavioral/strategy/main.py b/behavioral/strategy/main.py new file mode 100644 index 0000000..615dd89 --- /dev/null +++ b/behavioral/strategy/main.py @@ -0,0 +1,15 @@ +""" +The client code picks a concrete strategy and passes it to the context. +The client should be aware of the differences between strategies in order to make the right choice. +""" +from behavioral.strategy.concrete_strategies import ConcreteStrategyA, ConcreteStrategyB +from behavioral.strategy.context import Context + +context = Context(ConcreteStrategyA()) +print("Client: Strategy is set to normal sorting.") +context.do_some_business_logic() +print() + +print("Client: Strategy is set to reverse sorting.") +context.strategy = ConcreteStrategyB() +context.do_some_business_logic() diff --git a/behavioral/strategy/strategy.py b/behavioral/strategy/strategy.py new file mode 100644 index 0000000..0ac6c02 --- /dev/null +++ b/behavioral/strategy/strategy.py @@ -0,0 +1,15 @@ +from abc import ABC, abstractmethod + + +class Strategy(ABC): + """ + The Strategy interface declares operations common to all supported versions + of some algorithm. + + The Context uses this interface to call the algorithm defined by Concrete + Strategies. + """ + + @abstractmethod + def do_algorithm(self, data: list): + pass