Цепочка обязанностей
Цепочка обязанностей (англ. 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)
Ссылки
Примечания
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia