Цепочка обязанностей — Википедия
Цепочка обязанностей | |
---|---|
Chain of responsibility | |
![]() | |
Тип | поведенческий |
Назначение | для организации в системе уровней ответственности |
Родственные шаблоны | Компоновщик |
Описан в Design Patterns | Да |
Цепочка обязанностей (англ. Chain of responsibility) — поведенческий шаблон проектирования, предназначенный для организации в системе уровней ответственности.
Применение
[править | править код]Шаблон рекомендован для использования в условиях:
- в разрабатываемой системе имеется группа объектов, которые могут обрабатывать сообщения определенного типа;
- все сообщения должны быть обработаны хотя бы одним объектом системы;
- сообщения в системе обрабатываются по схеме «обработай сам либо перешли другому», то есть одни сообщения обрабатываются на том уровне, где они получены, а другие пересылаются объектам иного уровня.
Примеры
[править | править код]Пример на Swift
[править | править код]Исходный текст на Swift
class Error { var statusCode = 500 } protocol HandleErrorProtocol { var statusCodes: ClosedRange<Int> { get } var nextError: HandleErrorProtocol? { get set } func getStatusCode(statusCode: Int) } class SuccessRequest: HandleErrorProtocol { var nextError: HandleErrorProtocol? = ClientErrors() var statusCodes = 200...299 func getStatusCode(statusCode: Int) { statusCodes.contains(statusCode) ? print("Handle good request") : nextError?.getStatusCode(statusCode: statusCode) } } class ClientErrors: HandleErrorProtocol { var nextError: HandleErrorProtocol? = ServerErrors() var statusCodes = 400...499 func getStatusCode(statusCode: Int) { statusCodes.contains(statusCode) ? print("Handle client error") : nextError?.getStatusCode(statusCode: statusCode) } } class ServerErrors: HandleErrorProtocol { var nextError: HandleErrorProtocol? var statusCodes = 500...599 func getStatusCode(statusCode: Int) { statusCodes.contains(statusCode) ? print("Handle server error") : print("Cannot identify error") } } let error = Error() let request = SuccessRequest() request.getStatusCode(statusCode: error.statusCode)
Пример на PHP 5
[править | править код]Исходный текст на PHP 5.3
namespace ChainOfResponsibility { abstract class Logger { const ERR = 3; const NOTICE = 5; const DEBUG = 7; protected $mask; // Следующий элемент в цепочке обязанностей protected $next; public function __construct($mask) { $this->mask = $mask; } public function setNext(Logger $log) { $this->next = $log; return $log; } public function message($msg, $priority) { if ($priority <= $this->mask) { $this->writeMessage($msg); } if ($this->next != null) { $this->next->message($msg, $priority); } } protected abstract function writeMessage($msg); } class StdoutLogger extends Logger { protected function writeMessage($msg) { echo sprintf("Writing to stdout:%s\n", $msg); } } class EmailLogger extends Logger { protected function writeMessage($msg) { echo sprintf("Sending via email:%s\n", $msg); } } class StderrLogger extends Logger { protected function writeMessage($msg) { echo sprintf("Sending to stderr:%s\n", $msg); } } //цепочка обязанностей class ChainOfResponsibilityExample { public function run() { // строим цепочку обязанностей $logger = new StdoutLogger(Logger::DEBUG); $logger1 = $logger->setNext(new EmailLogger(Logger::NOTICE)); $logger2 = $logger1->setNext(new StderrLogger(Logger::ERR)); // Handled by StdoutLogger $logger->message("Entering function y.", Logger::DEBUG); // Handled by StdoutLogger and EmailLogger $logger->message("Step1 completed.", Logger::NOTICE); // Handled by all three loggers $logger->message("An error has occurred.", Logger::ERR); } } $chain = new ChainOfResponsibilityExample(); $chain->run(); }
Пример на Java
[править | править код]Исходный текст на Java
package chainofresp; abstract class Logger { public static int ERR = 3; public static int NOTICE = 5; public static int DEBUG = 7; protected int mask; // The next element in the chain of responsibility protected Logger next; public Logger setNext(Logger log) { next = log; return log; } public void message(String msg, int priority) { if (priority <= mask) { writeMessage(msg); } if (next != null) { next.message(msg, priority); } } abstract protected void writeMessage(String msg); } class StdoutLogger extends Logger { public StdoutLogger(int mask) { this.mask = mask; } protected void writeMessage(String msg) { System.out.println("Writing to stdout: " + msg); } } class EmailLogger extends Logger { public EmailLogger(int mask) { this.mask = mask; } protected void writeMessage(String msg) { System.out.println("Sending via email: " + msg); } } class StderrLogger extends Logger { public StderrLogger(int mask) { this.mask = mask; } protected void writeMessage(String msg) { System.out.println("Sending to stderr: " + msg); } } public class ChainOfResponsibilityExample { public static void main(String[] args) { // Build the chain of responsibility Logger logger, logger1,logger2; logger = new StdoutLogger(Logger.DEBUG); logger1 = logger.setNext(new EmailLogger(Logger.NOTICE)); logger2 = logger1.setNext(new StderrLogger(Logger.ERR)); // Handled by StdoutLogger logger.message("Entering function y.", Logger.DEBUG); // Handled by StdoutLogger and EmailLogger logger.message("Step1 completed.", Logger.NOTICE); // Handled by all three loggers logger.message("An error has occurred.", Logger.ERR); } } /* The output is: Writing to stdout: Entering function y. Writing to stdout: Step1 completed. Sending via e-mail: Step1 completed. Writing to stdout: An error has occurred. Sending via e-mail: An error has occurred. Sending to stderr: An error has occurred. */
Пример на C#
[править | править код]Исходный текст на языке C#
// Chain of Responsibility pattern -- Structural example using System; namespace DoFactory.GangOfFour.Chain.Structural { /// <summary> /// MainApp startup class for Structural /// Chain of Responsibility Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main() { // Setup Chain of Responsibility Handler h1 = new ConcreteHandler1(); Handler h2 = new ConcreteHandler2(); Handler h3 = new ConcreteHandler3(); h1.SetSuccessor(h2); h2.SetSuccessor(h3); // Generate and process request int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 }; foreach (int request in requests) { h1.HandleRequest(request); } // Wait for user Console.ReadKey(); } } /// <summary> /// The 'Handler' abstract class /// </summary> abstract class Handler { protected Handler successor; public void SetSuccessor(Handler successor) { this.successor = successor; } public abstract void HandleRequest(int request); } /// <summary> /// The 'ConcreteHandler1' class /// </summary> class ConcreteHandler1 : Handler { public override void HandleRequest(int request) { if (request >= 0 && request < 10) { Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } /// <summary> /// The 'ConcreteHandler2' class /// </summary> class ConcreteHandler2 : Handler { public override void HandleRequest(int request) { if (request >= 10 && request < 20) { Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } /// <summary> /// The 'ConcreteHandler3' class /// </summary> class ConcreteHandler3 : Handler { public override void HandleRequest(int request) { if (request >= 20 && request < 30) { Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } } Output ConcreteHandler1 handled request 2 ConcreteHandler1 handled request 5 ConcreteHandler2 handled request 14 ConcreteHandler3 handled request 22 ConcreteHandler2 handled request 18 ConcreteHandler1 handled request 3 ConcreteHandler3 handled request 27 ConcreteHandler3 handled request 20
Пример на C++
[править | править код]Исходный текст на языке C++
#include <iostream> /** * Вспомогательный класс, описывающий некоторое преступление */ class CriminalAction { friend class Policeman; // Полицейские имеют доступ к материалам следствия int complexity; // Сложность дела const char* description; // Краткое описание преступления public: CriminalAction(int complexity, const char* description): complexity(complexity), description(description) {} }; /** * Абстрактный полицейский, который может заниматься расследованием преступлений */ class Policeman { protected: int deduction; // дедукция (умение распутывать сложные дела) у данного полицейского Policeman* next; // более умелый полицейский, который получит дело, если для текущего оно слишком сложное virtual void investigateConcrete(const char* description) {} // собственно расследование public: Policeman(int deduction) : deduction(deduction), next(nullptr) {} virtual ~Policeman() { delete next; } /** * Добавляет в цепочку ответственности более опытного полицейского, который сможет принять на себя * расследование, если текущий не справится */ Policeman* setNext(Policeman* policeman) { next = policeman; return next; } /** * Полицейский начинает расследование или, если дело слишком сложное, передает его более опытному коллеге */ void investigate(CriminalAction* criminalAction) { if (deduction < criminalAction->complexity) { if (next) { next->investigate(criminalAction); } else { std::cout << "Это дело не раскрыть никому." << std::endl; } } else { investigateConcrete(criminalAction->description); } } }; class MartinRiggs: public Policeman { protected: void investigateConcrete(const char* description) { std::cout << "Расследование по делу \"" << description << "\" ведет сержант Мартин Риггс" << std::endl; } public: MartinRiggs(int deduction): Policeman(deduction) {} }; class JohnMcClane: public Policeman { protected: void investigateConcrete(const char* description) { std::cout << "Расследование по делу \"" << description << "\" ведет детектив Джон Макклейн" << std::endl; } public: JohnMcClane(int deduction): Policeman(deduction) {} }; class VincentHanna: public Policeman { protected: void investigateConcrete(const char* description) { std::cout << "Расследование по делу \"" << description << "\" ведет лейтенант Винсент Ханна" << std::endl; } public: VincentHanna(int deduction): Policeman(deduction) {} }; int main() { std::cout << "OUTPUT:" << std::endl; Policeman* policeman = new MartinRiggs(3); // полицейский с наименьшим навыком ведения расследований policeman ->setNext(new JohnMcClane(5)) ->setNext(new VincentHanna(8)); // добавляем ему двух опытных коллег policeman->investigate(new CriminalAction(2, "Торговля наркотиками из Вьетнама")); policeman->investigate(new CriminalAction(7, "Дерзкое ограбление банка в центре Лос-Анджелеса")); policeman->investigate(new CriminalAction(5, "Серия взрывов в центре Нью-Йорка")); return 0; } /** * OUTPUT: * Расследование по делу "Торговля наркотиками из Вьетнама" ведет сержант Мартин Риггс * Расследование по делу "Дерзкое ограбление банка в центре Лос-Анджелеса" ведет лейтенант Винсент Ханна * Расследование по делу "Серия взрывов в центре Нью-Йорка" ведет детектив Джон Макклейн */
Пример на Python
[править | править код]Исходный текст на языке Python
handlers = [] def car_handler(func): handlers.append(func) return func class Car: def __init__(self): self.name = None self.km = 11100 self.fuel = 5 self.oil = 5 @car_handler def handle_fuel(car): if car.fuel < 10: print("added fuel") car.fuel = 100 @car_handler def handle_km(car): if car.km > 10000: print("made a car test.") car.km = 0 @car_handler def handle_oil(car): if car.oil < 10: print("Added oil") car.oil = 100 class Garage: def __init__(self, handlers=None): self.handlers = handlers or [] def add_handler(self, handler): self.handlers.append(handler) def handle_car(self, car): for handler in self.handlers: handler(car) if __name__ == '__main__': garage = Garage(handlers) car = Car() garage.handle_car(car)
Ссылки
[править | править код]- Паттерн Chain of Responsibility (цепочка обязанностей) — назначение, описание, особенности и реализация на C++.
Примечания
[править | править код]