Autumn SALE
Łańcuch zobowiązań

Łańcuch zobowiązań w języku C#

Łańcuch zobowiązań to behawioralny wzorzec projektowy pozwalający przekazywać żądanie wzdłuż łańcucha potencjalnych obiektów obsługujących aż zostanie obsłużone.

W łańcuchu zobowiązań wiele obiektów może obsłużyć żądanie bez konieczności sprzęgania klas wysyłających je z konkretnymi klasami odbierającymi. Łańcuch można układać dynamicznie w trakcie działania programu z dowolnych obiektów obsługujących, wyposażonych w standardowy interfejs obsługi żądań.

Złożoność:

Popularność:

Przykłady użycia: Łańcuch zobowiązań jest rzadkim rozwiązaniem w programach napisanych w C#, gdyż ma sens tylko w tym kodzie, w którym występują łańcuchy obiektów.

Identyfikacja: Wzorzec można rozpoznać na podstawie obecności behawioralnych metod jednej grupy obiektów pośrednio wywołujących analogiczne metody w innych obiektach za pośrednictwem wspólnego interfejsu.

Przykład koncepcyjny

Poniższy przykład ilustruje strukturę wzorca Łańcuch zobowiązań ze szczególnym naciskiem na następujące kwestie:

  • Z jakich składa się klas?
  • Jakie role pełnią te klasy?
  • W jaki sposób elementy wzorca są ze sobą powiązane?

Program.cs: Przykład koncepcyjny

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: Wynik działania

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.

Łańcuch zobowiązań w innych językach

Łańcuch zobowiązań w języku C++ Łańcuch zobowiązań w języku Go Łańcuch zobowiązań w języku Java Łańcuch zobowiązań w języku PHP Łańcuch zobowiązań w języku Python Łańcuch zobowiązań w języku Ruby Łańcuch zobowiązań w języku Rust Łańcuch zobowiązań w języku Swift Łańcuch zobowiązań w języku TypeScript