Ланцюжок обов'язків на C#
Ланцюжок обов’язків — це поведінковий патерн, що дозволяє передавати запит ланцюжком потенційних обробників до тих пір, поки один з них не обробить його.
Позбавляє від жорсткої прив’язки відправника запиту до одержувача, дозволяючи динамічно вибудовувати ланцюг з різних обробників.
Складність:
Популярність:
Застосування: Патерн зустрічається в C# не так вже й часто, оскільки для його застосування потрібен ланцюг об’єктів, наприклад, зв’язаний список.
Ознаки застосування патерна: Ланцюжок обов’язків можна визначити за списками обробників або перевірок, через які пропускаються запити. Особливо, якщо порядок проходження обробників є важливим.
Концептуальний приклад
Цей приклад показує структуру патерна Ланцюжок обов’язків , а саме — з яких класів він складається, які ролі ці класи виконують і як вони взаємодіють один з одним.
Program.cs: Приклад структури патерна
using System;
using System.Collections.Generic;
namespace RefactoringGuru.DesignPatterns.ChainOfResponsibility.Conceptual
{
// The Handler interface declares a method for building the chain of
// handlers. It also declares a method for executing a request.
public interface IHandler
{
IHandler SetNext(IHandler handler);
object Handle(object request);
}
// The default chaining behavior can be implemented inside a base handler
// class.
abstract class AbstractHandler : IHandler
{
private IHandler _nextHandler;
public IHandler SetNext(IHandler handler)
{
this._nextHandler = handler;
// Returning a handler from here will let us link handlers in a
// convenient way like this:
// monkey.SetNext(squirrel).SetNext(dog);
return handler;
}
public virtual object Handle(object request)
{
if (this._nextHandler != null)
{
return this._nextHandler.Handle(request);
}
else
{
return null;
}
}
}
class MonkeyHandler : AbstractHandler
{
public override object Handle(object request)
{
if ((request as string) == "Banana")
{
return $"Monkey: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}
class SquirrelHandler : AbstractHandler
{
public override object Handle(object request)
{
if (request.ToString() == "Nut")
{
return $"Squirrel: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}
class DogHandler : AbstractHandler
{
public override object Handle(object request)
{
if (request.ToString() == "MeatBall")
{
return $"Dog: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}
class Client
{
// 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.
public static void ClientCode(AbstractHandler handler)
{
foreach (var food in new List<string> { "Nut", "Banana", "Cup of coffee" })
{
Console.WriteLine($"Client: Who wants a {food}?");
var result = handler.Handle(food);
if (result != null)
{
Console.Write($" {result}");
}
else
{
Console.WriteLine($" {food} was left untouched.");
}
}
}
}
class Program
{
static void Main(string[] args)
{
// The other part of the client code constructs the actual chain.
var monkey = new MonkeyHandler();
var squirrel = new SquirrelHandler();
var dog = new DogHandler();
monkey.SetNext(squirrel).SetNext(dog);
// The client should be able to send a request to any handler, not
// just the first one in the chain.
Console.WriteLine("Chain: Monkey > Squirrel > Dog\n");
Client.ClientCode(monkey);
Console.WriteLine();
Console.WriteLine("Subchain: Squirrel > Dog\n");
Client.ClientCode(squirrel);
}
}
}
Output.txt: Результат виконання
Chain: Monkey > Squirrel > Dog
Client: Who wants a Nut?
Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
Monkey: I'll eat the Banana.
Client: Who wants a Cup of coffee?
Cup of coffee was left untouched.
Subchain: Squirrel > Dog
Client: Who wants a Nut?
Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
Banana was left untouched.
Client: Who wants a Cup of coffee?
Cup of coffee was left untouched.
Ланцюжок обов'язків іншими мовами програмування