Цепочка обязанностей
Цепочка обязанностей (англ. 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# int[] requests = [2, 5, 14, 22, 18, 3, 27, 20];
Handler handler = new Handler_0To10 {
Successor = new Handler_10To20 {
Successor = new Handler_20To30()
}};
foreach (var req in requests)
handler.HandleRequest(req);
abstract class Handler
{
public Handler? Successor { protected get; set; }
public void HandleRequest(int req)
{
if (CanHandle(req)) Handle(req);
else Successor?.HandleRequest(req);
}
protected abstract bool CanHandle(int req);
// In this simple demo all inheritors have the same implementation.
// They only call the 'Print' method.
protected abstract void Handle(int req);
protected void Print(int req)
=> Console.WriteLine($"req: {req,2} handler: '{GetType().Name}'");
}
class Handler_0To10 : Handler
{
protected override bool CanHandle(int req) => req is >= 0 and < 10;
protected override void Handle(int req) => Print(req);
}
class Handler_10To20 : Handler
{
protected override bool CanHandle(int req) => req is >= 10 and < 20;
protected override void Handle(int req) => Print(req);
}
class Handler_20To30 : Handler
{
protected override bool CanHandle(int req) => req is >= 20 and < 30;
protected override void Handle(int req) => Print(req);
}
// Output
// req: 2 handler: 'Handler_0To10'
// req: 5 handler: 'Handler_0To10'
// req: 14 handler: 'Handler_10To20'
// req: 22 handler: 'Handler_20To30'
// req: 18 handler: 'Handler_10To20'
// req: 3 handler: 'Handler_0To10'
// req: 27 handler: 'Handler_20To30'
// req: 20 handler: 'Handler_20To30'
Пример на 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