development:software-architecture:design-patterns:chain-of-responsibility
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
development:software-architecture:design-patterns:chain-of-responsibility [2024/08/23 04:51] – tungnt | development:software-architecture:design-patterns:chain-of-responsibility [2024/08/24 03:28] (current) – tungnt | ||
---|---|---|---|
Line 3: | Line 3: | ||
https:// | https:// | ||
+ | {{ : | ||
+ | {{ : | ||
+ | |||
+ | **Ví dụ 1:** | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | namespace RefactoringGuru\ChainOfResponsibility\Conceptual; | ||
+ | |||
+ | /** | ||
+ | * The Handler interface declares a method for building the chain of handlers. | ||
+ | * It also declares a method for executing a request. | ||
+ | */ | ||
+ | interface Handler | ||
+ | { | ||
+ | public function setNext(Handler $handler): Handler; | ||
+ | |||
+ | public function handle(string $request): ?string; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The default chaining behavior can be implemented inside a base handler class. | ||
+ | */ | ||
+ | abstract class AbstractHandler implements Handler | ||
+ | { | ||
+ | /** | ||
+ | * @var Handler | ||
+ | */ | ||
+ | private $nextHandler; | ||
+ | |||
+ | public function setNext(Handler $handler): Handler | ||
+ | { | ||
+ | $this-> | ||
+ | // Returning a handler from here will let us link handlers in a | ||
+ | // convenient way like this: | ||
+ | // $monkey-> | ||
+ | return $handler; | ||
+ | } | ||
+ | |||
+ | public function handle(string $request): ?string | ||
+ | { | ||
+ | if ($this-> | ||
+ | return $this-> | ||
+ | } | ||
+ | |||
+ | return null; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * All Concrete Handlers either handle a request or pass it to the next handler | ||
+ | * in the chain. | ||
+ | */ | ||
+ | class MonkeyHandler extends AbstractHandler | ||
+ | { | ||
+ | public function handle(string $request): ?string | ||
+ | { | ||
+ | if ($request === " | ||
+ | return " | ||
+ | } else { | ||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class SquirrelHandler extends AbstractHandler | ||
+ | { | ||
+ | public function handle(string $request): ?string | ||
+ | { | ||
+ | if ($request === " | ||
+ | return " | ||
+ | } else { | ||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class DogHandler extends AbstractHandler | ||
+ | { | ||
+ | public function handle(string $request): ?string | ||
+ | { | ||
+ | if ($request === " | ||
+ | return "Dog: I'll eat the " . $request . " | ||
+ | } else { | ||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * 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. | ||
+ | */ | ||
+ | function clientCode(Handler $handler) | ||
+ | { | ||
+ | foreach ([" | ||
+ | echo " | ||
+ | $result = $handler-> | ||
+ | if ($result) { | ||
+ | echo " | ||
+ | } else { | ||
+ | echo " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The other part of the client code constructs the actual chain. | ||
+ | */ | ||
+ | $monkey = new MonkeyHandler(); | ||
+ | $squirrel = new SquirrelHandler(); | ||
+ | $dog = new DogHandler(); | ||
+ | |||
+ | $monkey-> | ||
+ | |||
+ | /** | ||
+ | * The client should be able to send a request to any handler, not just the | ||
+ | * first one in the chain. | ||
+ | */ | ||
+ | echo " | ||
+ | clientCode($monkey); | ||
+ | echo " | ||
+ | |||
+ | echo " | ||
+ | clientCode($squirrel); | ||
+ | </ | ||
+ | |||
+ | **Ví dụ 2:** | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | namespace RefactoringGuru\ChainOfResponsibility\RealWorld; | ||
+ | |||
+ | /** | ||
+ | * The classic CoR pattern declares a single role for objects that make up a | ||
+ | * chain, which is a Handler. In our example, let's differentiate between | ||
+ | * middleware and a final application' | ||
+ | * request gets through all the middleware objects. | ||
+ | * | ||
+ | * The base Middleware class declares an interface for linking middleware | ||
+ | * objects into a chain. | ||
+ | */ | ||
+ | abstract class Middleware | ||
+ | { | ||
+ | /** | ||
+ | * @var Middleware | ||
+ | */ | ||
+ | private $next; | ||
+ | |||
+ | /** | ||
+ | * This method can be used to build a chain of middleware objects. | ||
+ | */ | ||
+ | public function linkWith(Middleware $next): Middleware | ||
+ | { | ||
+ | $this-> | ||
+ | |||
+ | return $next; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Subclasses must override this method to provide their own checks. A | ||
+ | * subclass can fall back to the parent implementation if it can't process a | ||
+ | * request. | ||
+ | */ | ||
+ | public function check(string $email, string $password): bool | ||
+ | { | ||
+ | if (!$this-> | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | return $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This Concrete Middleware checks whether a user with given credentials exists. | ||
+ | */ | ||
+ | class UserExistsMiddleware extends Middleware | ||
+ | { | ||
+ | private $server; | ||
+ | |||
+ | public function __construct(Server $server) | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function check(string $email, string $password): bool | ||
+ | { | ||
+ | if (!$this-> | ||
+ | echo " | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if (!$this-> | ||
+ | echo " | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This Concrete Middleware checks whether a user associated with the request | ||
+ | * has sufficient permissions. | ||
+ | */ | ||
+ | class RoleCheckMiddleware extends Middleware | ||
+ | { | ||
+ | public function check(string $email, string $password): bool | ||
+ | { | ||
+ | if ($email === " | ||
+ | echo " | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | echo " | ||
+ | |||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This Concrete Middleware checks whether there are too many failed login | ||
+ | * requests. | ||
+ | */ | ||
+ | class ThrottlingMiddleware extends Middleware | ||
+ | { | ||
+ | private $requestPerMinute; | ||
+ | |||
+ | private $request; | ||
+ | |||
+ | private $currentTime; | ||
+ | |||
+ | public function __construct(int $requestPerMinute) | ||
+ | { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Please, note that the parent:: | ||
+ | * beginning of this method and at the end. | ||
+ | * | ||
+ | * This gives much more flexibility than a simple loop over all middleware | ||
+ | * objects. For instance, a middleware can change the order of checks by | ||
+ | * running its check after all the others. | ||
+ | */ | ||
+ | public function check(string $email, string $password): bool | ||
+ | { | ||
+ | if (time() > $this-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | $this-> | ||
+ | |||
+ | if ($this-> | ||
+ | echo " | ||
+ | die(); | ||
+ | } | ||
+ | |||
+ | return parent:: | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This is an application' | ||
+ | * uses the CoR pattern to execute a set of various authentication middleware | ||
+ | * before launching some business logic associated with a request. | ||
+ | */ | ||
+ | class Server | ||
+ | { | ||
+ | private $users = []; | ||
+ | |||
+ | /** | ||
+ | * @var Middleware | ||
+ | */ | ||
+ | private $middleware; | ||
+ | |||
+ | /** | ||
+ | * The client can configure the server with a chain of middleware objects. | ||
+ | */ | ||
+ | public function setMiddleware(Middleware $middleware): | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The server gets the email and password from the client and sends the | ||
+ | * authorization request to the middleware. | ||
+ | */ | ||
+ | public function logIn(string $email, string $password): bool | ||
+ | { | ||
+ | if ($this-> | ||
+ | echo " | ||
+ | |||
+ | // Do something useful for authorized users. | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public function register(string $email, string $password): void | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function hasEmail(string $email): bool | ||
+ | { | ||
+ | return isset($this-> | ||
+ | } | ||
+ | |||
+ | public function isValidPassword(string $email, string $password): bool | ||
+ | { | ||
+ | return $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The client code. | ||
+ | */ | ||
+ | $server = new Server(); | ||
+ | $server-> | ||
+ | $server-> | ||
+ | |||
+ | // All middleware are chained. The client can build various configurations of | ||
+ | // chains depending on its needs. | ||
+ | $middleware = new ThrottlingMiddleware(2); | ||
+ | $middleware | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | // The server gets a chain from the client code. | ||
+ | $server-> | ||
+ | |||
+ | // ... | ||
+ | |||
+ | do { | ||
+ | echo " | ||
+ | $email = readline(); | ||
+ | echo "Enter your password: | ||
+ | $password = readline(); | ||
+ | $success = $server-> | ||
+ | } while (!$success); | ||
+ | </ |
development/software-architecture/design-patterns/chain-of-responsibility.1724388703.txt.gz · Last modified: by tungnt