From 976dc2c5ca47a0548e81620407d3355d42b505f8 Mon Sep 17 00:00:00 2001 From: Ruidy Date: Wed, 30 Sep 2020 14:10:37 +0200 Subject: [PATCH] add code example --- .../chain_responsibility/abstract_handler.py | 27 ++++++++++++++ .../chain_responsibility/concrete_handlers.py | 28 +++++++++++++++ behavioral/chain_responsibility/handler.py | 19 ++++++++++ behavioral/chain_responsibility/main.py | 35 +++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 behavioral/chain_responsibility/abstract_handler.py create mode 100644 behavioral/chain_responsibility/concrete_handlers.py create mode 100644 behavioral/chain_responsibility/handler.py create mode 100644 behavioral/chain_responsibility/main.py diff --git a/behavioral/chain_responsibility/abstract_handler.py b/behavioral/chain_responsibility/abstract_handler.py new file mode 100644 index 0000000..e6c2b53 --- /dev/null +++ b/behavioral/chain_responsibility/abstract_handler.py @@ -0,0 +1,27 @@ +from abc import abstractmethod +from typing import Any, Optional + +from behavioral.chain_responsibility.handler import Handler + + +class AbstractHandler(Handler): + """ + The default chaining behavior can be implemented inside a base handler + class. + """ + + _next_handler: Handler = None + + def set_next(self, handler: Handler) -> Handler: + self._next_handler = handler + # Returning a handler from here will let us link handlers in a + # convenient way like this: + # monkey.set_next(squirrel).set_next(dog) + return handler + + @abstractmethod + def handle(self, request: Any) -> Optional[str]: + if self._next_handler: + return self._next_handler.handle(request) + + return None diff --git a/behavioral/chain_responsibility/concrete_handlers.py b/behavioral/chain_responsibility/concrete_handlers.py new file mode 100644 index 0000000..3290a8d --- /dev/null +++ b/behavioral/chain_responsibility/concrete_handlers.py @@ -0,0 +1,28 @@ +""" +All Concrete Handlers either handle a request or pass it to the next handler in +the chain. +""" +from typing import Optional, Any + +from behavioral.chain_responsibility.abstract_handler import AbstractHandler + + +class MonkeyHandler(AbstractHandler): + def handle(self, request: Any) -> Optional[str]: + if request == 'Banana': + return f"Monkey: I'll eat the {request}" + return super().handle(request) + + +class SquirrelHandler(AbstractHandler): + def handle(self, request: Any) -> Optional[str]: + if request == 'Nut': + return f"Squirrel: I'll eat the {request}" + return super().handle(request) + + +class DogHandler(AbstractHandler): + def handle(self, request: Any) -> Optional[str]: + if request == 'MeatBall': + return f"Dog: I'll eat the {request}" + return super().handle(request) diff --git a/behavioral/chain_responsibility/handler.py b/behavioral/chain_responsibility/handler.py new file mode 100644 index 0000000..247dfff --- /dev/null +++ b/behavioral/chain_responsibility/handler.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Optional, Any + + +class Handler(ABC): + """ + The Handler interface declares a method for building the chain of handlers. + It also declares a method for executing a request. + """ + + @abstractmethod + def set_next(self, handler: Handler) -> Handler: + pass + + @abstractmethod + def handle(self, request: Any) -> Optional[str]: + pass diff --git a/behavioral/chain_responsibility/main.py b/behavioral/chain_responsibility/main.py new file mode 100644 index 0000000..c5cbbcd --- /dev/null +++ b/behavioral/chain_responsibility/main.py @@ -0,0 +1,35 @@ +from behavioral.chain_responsibility.concrete_handlers import MonkeyHandler, SquirrelHandler, DogHandler +from behavioral.chain_responsibility.handler import Handler + + +def client_code(handler: Handler): + """ + The client code is usually suited to work with a single handler. In most + cases, it is not even aware that the handler is part of a chain. + """ + + for food in ["Nut", "Banana", "Cup of coffee"]: + print(f"\nClient: Who wants a {food}?") + result = handler.handle(food) + + if result: + print(f" {result}", end="") + else: + print(f" {food} was left untouched.", end="") + + +if __name__ == '__main__': + monkey = MonkeyHandler() + squirrel = SquirrelHandler() + dog = DogHandler() + + monkey.set_next(squirrel).set_next(dog) + + # The client should be able to send a request to any handler, not just the + # first one in the chain. + print("Chain: Monkey > Squirrel > Dog") + client_code(monkey) + print("\n") + + print("Subchain: Squirrel > Dog") + client_code(squirrel)