**نمط سلسلة المسؤولية بالانجليزية (Chain-of-responsibility pattern)** في التصميم الكائني التوجه هو نمط تصميم سلوكي يتكون من مصدر كائنات الأمر وسلسلة من **كائنات المعالجة**. يحتوي كل كائن معالجة على منطق يحدد أنواع كائنات الأوامر التي يمكنه معالجتها ؛ يتم تمرير الباقي إلى كائن المعالجة التالي في السلسلة. توجد أيضًا آلية لإضافة كائنات معالجة جديدة إلى نهاية هذه السلسلة.

في تباين نموذج سلسلة المسؤولية القياسي، قد يعمل بعض المتعاملين كمرسلين، قادرين على إرسال الأوامر في مجموعة متنوعة من الاتجاهات، وتشكيل *شجرة المسؤولية*. في بعض الحالات، يمكن أن يحدث هذا بشكل متكرر، حيث تستدعي معالجة الكائنات كائنات معالجة أعلى بأوامر تحاول حل جزء أصغر من المشكلة ؛ في هذه الحالة، يستمر العودية حتى تتم معالجة الأمر، أو يتم استكشاف الشجرة بأكملها. قد يعمل مترجم XML بهذه الطريقة.

يروج هذا النمط لفكرة الاقتران السائب .

نمط سلسلة المسؤولية متطابق تقريبًا من الناحية الهيكلية مع نمط الديكور ، والفرق هو أنه بالنسبة لمصمم الديكور، تتعامل جميع الفئات مع الطلب، بينما بالنسبة لسلسلة المسؤولية، تتعامل إحدى الفئات في السلسلة بالضبط مع الطلب. هذا تعريف صارم لمفهوم المسؤولية في كتاب GoF. ومع ذلك، فإن العديد من التطبيقات (مثل المسجلات أدناه، أو معالجة حدث واجهة المستخدم، أو عوامل تصفية servlet في Java ، إلخ) تسمح للعديد من العناصر في السلسلة بتحمل المسؤولية.

الملخص
------

سلسلة المسؤولية  نمط التصميم هو واحد من ثلاثة وعشرين نمطًا معروفًا من *أنماط تصميم GoF* التي تصف الحلول المشتركة لمشاكل التصميم المتكررة عند تصميم برامج كائنية التوجه مرنة وقابلة لإعادة الاستخدام، أي كائنات يسهل تنفيذها، التغيير والاختبار وإعادة الاستخدام.

**ما هي المشاكل التي يمكن أن يحلها نمط تصميم سلسلة المسؤولية؟** 

* يجب تجنب اقتران مرسل الطلب بالمتلقي الخاص به.
* ينبغي أن يكون من الممكن أن يتعامل أكثر من جهاز استقبال مع الطلب.

### **ما الحل الذي يصفه نمط تصميم سلسلة المسؤولية؟**

يحدد سلسلة من كائنات المستقبل التي تتحمل المسؤولية، اعتمادًا على ظروف وقت التشغيل، إما للتعامل مع الطلب أو إعادة توجيهه إلى جهاز الاستقبال التالي على السلسلة (إن وجد).

يتيح لنا ذلك إرسال طلب إلى سلسلة من المستلمين دون الحاجة إلى معرفة الشخص الذي يتعامل مع الطلب. يتم تمرير الطلب على طول السلسلة حتى يعالج المستلم الطلب. لم يعد مرسل الطلب مقترنًا بمستقبل معين.

راجع أيضًا فئة UML ومخطط التسلسل أدناه.

البنية
------

### فئة UML ومخطط التسلسل

نموذج لفئة UML ومخطط تسلسل لنمط تصميم سلسلة المسؤولية.
في الرسم التخطيطي لفئة UML أعلاه، `Sender` إلى فئة مستقبل معينة مباشرة. بدلاً من ذلك، يشير `Sender` `Handler` لمعالجة الطلب ( `handler.handleRequest()` ) ، مما يجعل `Sender` مستقلاً عن المتلقي الذي يتعامل مع الطلب. و `Receiver1` ، `Receiver2` ، و `Receiver3` الطبقات على تنفيذ `Handler` واجهة إما عن طريق المناولة أو إعادة توجيه الطلب (تبعا للظروف وقت التشغيل).

يوضح الرسم التخطيطي لتسلسل UML تفاعلات وقت التشغيل: في هذا المثال، يستدعي كائن `Sender` `handleRequest()` على `receiver1` (من النوع `Handler` ). يقوم `receiver1` بإعادة توجيه الطلب إلى `receiver2` ، والذي بدوره يعيد توجيه الطلب إلى `receiver3` ، والذي يتعامل مع (ينفذ) الطلب.

### امثله

#### مثال جافا

يوجد أدناه مثال على هذا النمط في Java. يتم إنشاء المسجل باستخدام سلسلة من المسجلين، كل واحد تم تكوينه بمستويات سجل مختلفة.

```
import java.util.Arrays;
import java.util.EnumSet;
import java.util.function.Consumer;

@FunctionalInterface
public interface Logger {
 public enum LogLevel {
 INFO, DEBUG, WARNING, ERROR, FUNCTIONAL\_MESSAGE, FUNCTIONAL\_ERROR;

 public static LogLevel[] all() {
 return values();
 }
 }

 abstract void message(String msg, LogLevel severity);

 default Logger appendNext(Logger nextLogger) {
 return (msg, severity) -> {
 message(msg, severity);
 nextLogger.message(msg, severity);
 };
 }

 static Logger writeLogger(LogLevel[] levels, Consumer<String> stringConsumer) {
 EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
 return (msg, severity) -> {
 if (set.contains(severity)) {
 stringConsumer.accept(msg);
 }
 };
 }

 static Logger consoleLogger(LogLevel... levels) {
 return writeLogger(levels, msg -> System.err.println("Writing to console: "+ msg));
 }

 static Logger emailLogger(LogLevel... levels) {
 return writeLogger(levels, msg -> System.err.println("Sending via email: "+ msg));
 }

 static Logger fileLogger(LogLevel... levels) {
 return writeLogger(levels, msg -> System.err.println("Writing to Log File: "+ msg));
 }
}

class Runner {
 public static void main(String[] args) {
 // Build an immutable chain of responsibility
 Logger logger = consoleLogger(LogLevel.all())
 .appendNext(emailLogger(LogLevel.FUNCTIONAL\_MESSAGE, LogLevel.FUNCTIONAL\_ERROR))
 .appendNext(fileLogger(LogLevel.WARNING, LogLevel.ERROR));

 // Handled by consoleLogger since the console has a LogLevel of all
 logger.message("Entering function ProcessOrder().", LogLevel.DEBUG);
 logger.message("Order record retrieved.", LogLevel.INFO);

 // Handled by consoleLogger and emailLogger since emailLogger implements Functional\_Error & Functional\_Message
 logger.message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FUNCTIONAL\_ERROR);
 logger.message("Order Dispatched.", LogLevel.FUNCTIONAL\_MESSAGE);

 // Handled by consoleLogger and fileLogger since fileLogger implements Warning & Error
 logger.message("Customer Address details missing in Branch DataBase.", LogLevel.WARNING);
 logger.message("Customer Address details missing in Organization DataBase.", LogLevel.ERROR);
 }
}

```

#### لغة #C مثال

تستخدم أمثلة لغة #C هذه تطبيق المسجل لتحديد مصادر مختلفة بناءً على مستوى السجل

```
namespace ChainOfResponsibility
{
 [Flags]
 public enum LogLevel
 {
 None = 0, // 0
 Info = 1, // 1
 Debug = 2, // 10
 Warning = 4, // 100
 Error = 8, // 1000
 FunctionalMessage = 16, // 10000
 FunctionalError = 32, // 100000
 All = 63 // 111111
 }
 
 /// <summary>
 /// Abstract Handler in chain of responsibility pattern.
 /// </summary>
 public abstract class Logger
 {
 protected LogLevel logMask;
 
 // The next Handler in the chain
 protected Logger next;
 
 public Logger(LogLevel mask)
 {
 this.logMask = mask;
 }
 
 /// <summary>
 /// Sets the Next logger to make a list/chain of Handlers.
 /// </summary>
 public Logger SetNext(Logger nextlogger)
 {
 Logger lastLogger = this;

 while (lastLogger.next != null)
 {
 lastLogger = lastLogger.next;
 }

 lastLogger.next = nextlogger;
 return this;
 }
 
 public void Message(string msg, LogLevel severity)
 {
 if ((severity & logMask) != 0) // True only if any of the logMask bits are set in severity
 {
 WriteMessage(msg);
 }
 if (next != null) 
 {
 next.Message(msg, severity); 
 }
 }
 
 abstract protected void WriteMessage(string msg);
 }
 
 public class ConsoleLogger : Logger
 {
 public ConsoleLogger(LogLevel mask)
 : base(mask)
 { }
 
 protected override void WriteMessage(string msg)
 {
 Console.WriteLine("Writing to console: "+ msg);
 }
 }
 
 public class EmailLogger : Logger
 {
 public EmailLogger(LogLevel mask)
 : base(mask)
 { }
 
 protected override void WriteMessage(string msg)
 {
 // Placeholder for mail send logic, usually the email configurations are saved in config file.
 Console.WriteLine("Sending via email: "+ msg);
 }
 }
 
 class FileLogger : Logger
 {
 public FileLogger(LogLevel mask)
 : base(mask)
 { }
 
 protected override void WriteMessage(string msg)
 {
 // Placeholder for File writing logic
 Console.WriteLine("Writing to Log File: "+ msg);
 }
 }
 
 public class Program
 {
 public static void Main(string[] args)
 {
 // Build the chain of responsibility
 Logger logger;
 logger = new ConsoleLogger(LogLevel.All)
 .SetNext(new EmailLogger(LogLevel.FunctionalMessage | LogLevel.FunctionalError))
 .SetNext(new FileLogger(LogLevel.Warning | LogLevel.Error));
 
 // Handled by ConsoleLogger since the console has a loglevel of all
 logger.Message("Entering function ProcessOrder().", LogLevel.Debug);
 logger.Message("Order record retrieved.", LogLevel.Info);
 
 // Handled by ConsoleLogger and FileLogger since filelogger implements Warning & Error
 logger.Message("Customer Address details missing in Branch DataBase.", LogLevel.Warning);
 logger.Message("Customer Address details missing in Organization DataBase.", LogLevel.Error);
 
 // Handled by ConsoleLogger and EmailLogger as it implements functional error
 logger.Message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FunctionalError);
 
 // Handled by ConsoleLogger and EmailLogger
 logger.Message("Order Dispatched.", LogLevel.FunctionalMessage);
 }
 }
}
 
/\* Output
Writing to console: Entering function ProcessOrder().
Writing to console: Order record retrieved.
Writing to console: Customer Address details missing in Branch DataBase.
Writing to Log File: Customer Address details missing in Branch DataBase.
Writing to console: Customer Address details missing in Organization DataBase.
Writing to Log File: Customer Address details missing in Organization DataBase.
Writing to console: Unable to Process Order ORD1 Dated D1 For Customer C1.
Sending via email: Unable to Process Order ORD1 Dated D1 For Customer C1.
Writing to console: Order Dispatched.
Sending via email: Order Dispatched.
\*/

```

#### مثال الكريستال

```
enum LogLevel
 None
 Info
 Debug
 Warning
 Error
 FunctionalMessage
 FunctionalError
 All
end

abstract class Logger
 property log\_levels
 property next : Logger | Nil

 def initialize(\*levels)
 @log\_levels = [] of LogLevel

 levels.each do |level|
 @log\_levels << level
 end
 end

 def message(msg : String, severity : LogLevel)
 if @log\_levels.includes?(LogLevel::All) || @log\_levels.includes?(severity)
 write\_message(msg)
 end
 @next.try(&.message(msg, severity))
 end

 abstract def write\_message(msg : String)
end

class ConsoleLogger < Logger
 def write\_message(msg : String)
 puts "Writing to console: #{msg}"
 end
end

class EmailLogger < Logger
 def write\_message(msg : String)
 puts "Sending via email: #{msg}"
 end
end

class FileLogger < Logger
 def write\_message(msg : String)
 puts "Writing to Log File: #{msg}"
 end
end

# Program
# Build the chain of responsibility
logger = ConsoleLogger.new(LogLevel::All)
logger1 = logger.next = EmailLogger.new(LogLevel::FunctionalMessage, LogLevel::FunctionalError)
logger2 = logger1.next = FileLogger.new(LogLevel::Warning, LogLevel::Error)

# Handled by ConsoleLogger since the console has a loglevel of all
logger.message("Entering function ProcessOrder().", LogLevel::Debug)
logger.message("Order record retrieved.", LogLevel::Info)

# Handled by ConsoleLogger and FileLogger since filelogger implements Warning & Error
logger.message("Customer Address details missing in Branch DataBase.", LogLevel::Warning)
logger.message("Customer Address details missing in Organization DataBase.", LogLevel::Error)

# Handled by ConsoleLogger and EmailLogger as it implements functional error
logger.message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel::FunctionalError)

# Handled by ConsoleLogger and EmailLogger
logger.message("Order Dispatched.", LogLevel::FunctionalMessage)

```

#### بايثون2

```
"""
Chain of responsibility pattern example.
"""
from abc import ABCMeta, abstractmethod
from enum import Enum, auto

class LogLevel(Enum):
 """ Log Levels Enum."""
    NONE = auto()
    INFO = auto()
    DEBUG = auto()
    WARNING = auto()
    ERROR = auto()
    FUNCTIONAL\_MESSAGE = auto()
    FUNCTIONAL\_ERROR = auto()
    ALL = auto()

class Logger:
 """Abstract handler in chain of responsibility pattern."""
    \_\_metaclass\_\_ = ABCMeta

    next = None

    def \_\_init\_\_(self, levels) -> None:
 """Initialize new logger.

 Arguments:
 levels (list[str]): List of log levels.
 """
        self.log\_levels = []

        for level in levels:
            self.log\_levels.append(level)

    def set\_next(self, next\_logger: Logger):
 """Set next responsible logger in the chain.

 Arguments:
 next\_logger (Logger): Next responsible logger.
 Returns: Logger: Next responsible logger.
 """
        self.next = next\_logger
        return self.next

    def message(self, msg: str, severity: LogLevel) -> None:
 """Message writer handler.

 Arguments:
 msg (str): Message string.
 severity (LogLevel): Severity of message as log level enum.
 """
        if LogLevel.ALL in self.log\_levels or severity in self.log\_levels:
            self.write\_message(msg)

        if self.next is not None:
            self.next.message(msg, severity)

    @abstractmethod
    def write\_message(self, msg: str) -> None:
 """Abstract method to write a message.

 Arguments:
 msg (str): Message string.
 Raises: NotImplementedError
 """
        raise NotImplementedError("You should implement this method.")

class ConsoleLogger(Logger):
    def write\_message(self, msg: str) -> None:
 """Overrides parent's abstract method to write to console.

 Arguments:
 msg (str): Message string.
 """
        print("Writing to console:", msg)

class EmailLogger(Logger):
 """Overrides parent's abstract method to send an email.

 Arguments:
 msg (str): Message string.
 """
    def write\_message(self, msg: str) -> None:
        print(f"Sending via email: {msg}")

class FileLogger(Logger):
 """Overrides parent's abstract method to write a file.

 Arguments:
 msg (str): Message string.
 """
    def write\_message(self, msg: str) -> None:
        print(f"Writing to log file: {msg}")

def main():
 """Building the chain of responsibility."""
    logger = ConsoleLogger([LogLevel.ALL])
    email\_logger = logger.set\_next(
        EmailLogger([LogLevel.FUNCTIONAL\_MESSAGE, LogLevel.FUNCTIONAL\_ERROR])
    )
    # As we don't need to use file logger instance anywhere later
    # We will not set any value for it.
    email\_logger.set\_next(
        FileLogger([LogLevel.WARNING, LogLevel.ERROR])
    )

    # ConsoleLogger will handle this part of code since the message
    # has a log level of all
    logger.message("Entering function ProcessOrder().", LogLevel.DEBUG)
    logger.message("Order record retrieved.", LogLevel.INFO)

    # ConsoleLogger and FileLogger will handle this part since file logger
    # implements WARNING and ERROR
    logger.message(
        "Customer Address details missing in Branch DataBase.",
        LogLevel.WARNING
    )
    logger.message(
        "Customer Address details missing in Organization DataBase.",
        LogLevel.ERROR
    )

    # ConsoleLogger and EmailLogger will handle this part as they implement
    # functional error
    logger.message(
        "Unable to Process Order ORD1 Dated D1 for customer C1.",
        LogLevel.FUNCTIONAL\_ERROR
    )
    logger.message("OrderDispatched.", LogLevel.FUNCTIONAL\_MESSAGE)

if \_\_name\_\_ == "\_\_main\_\_":
    main()

```

#### مثال لغة PHP

```
<?php

abstract class Logger
{

    /\*\*
 \* Bitmask flags for severity.
 \*/
    public const NONE = 0;
    public const INFO = 0b000001;
    public const DEBUG = 0b000010;
    public const WARNING = 0b000100;
    public const ERROR = 0b001000;
    public const FUNCTIONAL\_MESSAGE = 0b010000;
    public const FUNCTIONAL\_ERROR = 0b100000;
    public const ALL = 0b111111;

    /\*\* @var int A bitmask flag from this class. \*/
    protected int $logMask;

    /\*\* @var \Logger|null An optional next logger to handle the message \*/
    protected ?Logger $next = null;

    /\*\*
 \* Logger constructor.
 \*
 \* @param int $mask
 \* A bitmask flag from this class.
 \*/
    public function \_\_construct(int $mask)
    {
        $this->logMask = $mask;
    }

    /\*\*
 \* Set next responsible logger in the chain.
 \*
 \* @param \Logger $nextLogger
 \* Next responsible logger.
 \*
 \* @return \Logger
 \* Logger: Next responsible logger.
 \*/
    public function setNext(Logger $nextLogger): Logger
    {
        $this->next = $nextLogger;

        return $nextLogger;
    }

    /\*\*
 \* Message writer handler.
 \*
 \* @param string $msg
 \* Message string.
 \* @param int $severity
 \* Severity of message as a bitmask flag from this class.
 \*
 \* @return $this
 \*/
    public function message(string $msg, int $severity): Logger
    {
        if ($severity & $this->logMask) {
            $this->writeMessage($msg);
        }
        if ($this->next !== null) {
            $this->next->message($msg, $severity);
        }

        return $this;
    }

    /\*\*
 \* Abstract method to write a message
 \*
 \* @param string $msg
 \* Message string.
 \*/
    abstract protected function writeMessage(string $msg): void;

}

class ConsoleLogger extends Logger
{

    protected function writeMessage(string $msg): void
    {
        echo "Writing to console: $msg\n";
    }

}

class EmailLogger extends Logger
{

    protected function writeMessage(string $msg): void
    {
        echo "Sending via email: $msg\n";
    }

}

class FileLogger extends Logger
{

    protected function writeMessage(string $msg): void
    {
        echo "Writing to a log file: $msg\n";
    }

}

$logger = new ConsoleLogger(Logger::ALL);
$logger
    ->setNext(new EmailLogger(Logger::FUNCTIONAL\_MESSAGE | Logger::FUNCTIONAL\_ERROR))
    ->setNext(new FileLogger(Logger::WARNING | Logger::ERROR));

$logger
    // Handled by ConsoleLogger since the console has a loglevel of all
    ->message("Entering function ProcessOrder().", Logger::DEBUG)
    ->message("Order record retrieved.", Logger::INFO)
    // Handled by ConsoleLogger and FileLogger since filelogger implements Warning & Error
    ->message("Customer Address details missing in Branch DataBase.", Logger::WARNING)
    ->message("Customer Address details missing in Organization DataBase.", Logger::ERROR)
    // Handled by ConsoleLogger and EmailLogger as it implements functional error
    ->message("Unable to Process Order ORD1 Dated D1 For Customer C1.", Logger::FUNCTIONAL\_ERROR)
    // Handled by ConsoleLogger and EmailLogger
    ->message("Order Dispatched.", Logger::FUNCTIONAL\_MESSAGE);

/\* Output
Writing to console: Entering function ProcessOrder().
Writing to console: Order record retrieved.
Writing to console: Customer Address details missing in Branch DataBase.
Writing to a log file: Customer Address details missing in Branch DataBase.
Writing to console: Customer Address details missing in Organization DataBase.
Writing to a log file: Customer Address details missing in Organization DataBase.
Writing to console: Unable to Process Order ORD1 Dated D1 For Customer C1.
Sending via email: Unable to Process Order ORD1 Dated D1 For Customer C1.
Writing to console: Order Dispatched.
Sending via email: Order Dispatched.
\*/

```

تطبيقات
-------

### كاكاو وكاكاو تاتش

تستخدم أطر Cocoa و Cocoa Touch ، المستخدمة في تطبيقات OS X وiOS على التوالي، بنشاط نمط سلسلة المسؤولية للتعامل مع الأحداث. تسمى الكائنات التي تشارك في السلسلة *كائنات المستجيب* ، وهي `NSResponder` من فئة NSResponder (OS X) / `UIResponder` (iOS). كافة الكائنات عرض ( `NSView` / `UIView` )، وكائنات رأي تحكم ( `NSViewController` / `UIViewController` )، والأشياء نافذة ( `NSWindow` / `UIWindow` )، والكائن التطبيق ( `NSApplication` / `UIApplication` ) هي كائنات الرد.

عادةً، عندما يتلقى أحد العروض حدثًا لا يمكنه التعامل معه، فإنه يرسله إلى العرض الإشرافي الخاص به حتى يصل إلى وحدة التحكم في العرض أو كائن النافذة. إذا لم تتمكن النافذة من معالجة الحدث، فسيتم إرسال الحدث إلى كائن التطبيق، وهو الكائن الأخير في السلسلة. على سبيل المثال:

* في OS X ، يمكن تحريك نافذة مزخرفة بالماوس من أي مكان (وليس فقط شريط العنوان) ، ما لم يكن هناك عرض في هذا الموقع يتعامل مع أحداث السحب، مثل عناصر التحكم في شريط التمرير. إذا لم يكن هناك مثل هذا العرض (أو العرض المشرف) ، فسيتم إرسال أحداث السحب لأعلى في السلسلة إلى النافذة التي تتعامل مع حدث السحب.
* في نظام التشغيل iOS ، من المعتاد التعامل مع أحداث العرض في وحدة التحكم في العرض التي تدير التسلسل الهرمي للعرض، بدلاً من تصنيف العرض نفسه. نظرًا لأن وحدة التحكم في العرض تقع في سلسلة المستجيب بعد جميع العروض الفرعية المُدارة، فيمكنها اعتراض أي أحداث عرض والتعامل معها.

انظر أيضًا
----------

* نمط تصميم البرامج
* مبدأ المهمة الواحدة

المراجع
-------

1. ↑  "Archived copy". مؤرشف من الأصل في 2018-02-27. اطلع عليه بتاريخ 2013-11-08.`{{استشهاد ويب}}`: صيانة الاستشهاد: الأرشيف كعنوان (link)
2. ↑  Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). *Design Patterns: Elements of Reusable Object-Oriented Software*. Addison Wesley. ص. 223ff. ISBN:0-201-63361-2.`{{استشهاد بكتاب}}`: صيانة الاستشهاد: أسماء متعددة: قائمة المؤلفين (link)
3. ↑  "The Chain of Responsibility design pattern - Problem, Solution, and Applicability". *w3sDesign.com*. مؤرشف من الأصل في 2021-11-18. اطلع عليه بتاريخ 2017-08-12.
4. ↑  "The Chain of Responsibility design pattern - Structure and Collaboration". *w3sDesign.com*. مؤرشف من الأصل في 2022-03-16. اطلع عليه بتاريخ 2017-08-12.

* أيقونة بوابةبوابة برمجيات
* أيقونة بوابةبوابة تقانة المعلومات
* أيقونة بوابةبوابة علم الحاسوب

|  |
| --- |
| **نمط سلسلة المسؤولية** في المشاريع الشقيقة: |
|  | 
* صور وملفات صوتية من كومنز.
 |