1. چیست الگوی زنجیره مسئولیت (Chain of Responsibility Pattern)

الگوی زنجیره مسئولیت یک الگوی طراحی رفتاری است که فرستنده و گیرنده درخواست را از یکدیگر جدا می‌کند و امکان دارد چندین شیء فرصتی را برای پردازش درخواست داشته باشند. هر گیرنده شامل یک مرجع به یک گیرنده دیگر است و اگر نتواند درخواست را پردازش کند، درخواست را به گیرنده بعدی منتقل می‌کند تا زمانی که درخواست پردازش شود یا به انتهای زنجیره برسد.

2. ویژگی‌ها و مزایای الگوی زنجیره مسئولیت (Chain of Responsibility Pattern)

ویژگی‌ها و مزایای الگوی زنجیره مسئولیت به شرح زیر است:

  • جداسازی فرستنده و گیرنده: فرستنده نیازی به این ندارد که در مورد چه گیرنده‌ای درخواست را پردازش می‌کند، یا نیازی به این نیست که در مورد گیرنده‌های خاص در زنجیره آگاه باشد.
  • انعطاف‌پذیری: این الگو به افزودن، حذف یا تغییر ترتیب گیرنده‌ها در زنجیره بدون تغییر کد فرستنده و گیرنده اجازه می‌دهد.
  • گسترش‌پذیری: افزودن آسان زنجیره مسئولیت با اضافه کردن گیرنده‌های خاص جدید.
  • اصل مسئولیت تک‌مسئولیتی: هر گیرنده خاص فقط باید در مورد منطق پردازش خود همتا باشد.
  • پیکربندی‌پذیری: زنجیره گیرنده‌ها بر اساس نیازها قابل پیکربندی است که اجازه می‌دهد درخواست‌های مختلف زنجیره‌های گیرنده مختلفی داشته باشند.

3. نمونه‌های کاربردی از الگوی زنجیره مسئولیت (Chain of Responsibility Pattern)

الگوی زنجیره مسئولیت کاربردهای عملی بسیاری دارد، مانند:

  • پردازش درخواست در برنامه‌های وب: می‌تواند برای پردازش انواع مختلف درخواست‌ها مانند احراز هویت، ثبت، و تأیید مجوز استفاده شود.
  • پردازش خطا: می‌تواند برای پردازش خطاها استفاده شود، به‌طوری که هر گیرنده مسئولیت پردازش یک نوع خاص از خطا را داشته و خطا را به گیرنده بعدی منتقل می‌کند.
  • پردازش رویداد: می‌تواند برای پردازش انواع مختلف رویدادها مانند رویداد کلیک کاربر، رویداد درخواست شبکه و غیره استفاده شود.

4. پیاده‌سازی الگوی زنجیره مسئولیت در گولنگ (Implementation of the Chain of Responsibility Pattern in Golang)

4.1 نمودار کلاس UML

الگوی زنجیره مسئولیت در گولنگ

4.2 معرفی مثال

در نمودار کلاس UML فوق، ما یک مدیر (Handler) انتزاعی و دو مدیر خاص (ConcreteHandler1 و ConcreteHandler2) تعریف کرده‌ایم. مشتری (Client) درخواست‌ها را با فراخوانی متد handleRequest مدیر راه‌اندازی می‌کند.

4.3 مرحله پیاده‌سازی 1: تعریف رابط مدیر انتزاعی

type Handler interface {
    HandleRequest(request Request) error
    SetNext(handler Handler)
}

type Request interface {
    Condition bool
}

رابط مدیر انتزاعی متد HandleRequest برای پردازش درخواست‌ها و متد SetNext برای تنظیم مدیر بعدی تعریف می‌کند.

4.4 مرحله پیاده‌سازی 2: پیاده‌سازی کلاس‌های مدیر خاص

type ConcreteHandler1 struct {
    next Handler
}

func (h *ConcreteHandler1) HandleRequest(request Request) error {
    // منطق برای پردازش درخواست
    if request.Condition {
        // کد برای پردازش درخواست
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("هیچ مدیری یافت نشد")
    }
}

func (h *ConcreteHandler1) SetNext(handler Handler) {
    h.next = handler
}

type ConcreteHandler2 struct {
    next Handler
}

func (h *ConcreteHandler2) HandleRequest(request Request) error {
    // منطق برای پردازش درخواست
    if request.Condition {
        // کد برای پردازش درخواست
        return nil
    } else {
        if h.next != nil {
            return h.next.HandleRequest(request)
        }
        return errors.New("هیچ مدیری یافت نشد")
    }
}

func (h *ConcreteHandler2) SetNext(handler Handler) {
    h.next = handler
}

کلاس‌های مدیر خاص رابط مدیر انتزاعی را پیاده‌سازی می‌کنند و متدهای HandleRequest و SetNext را override می‌کنند.

4.5 مرحله پیاده‌سازی 3: ساختن زنجیره مسئولیت

handler1 := &ConcreteHandler1{}
handler2 := &ConcreteHandler2{}

handler1.SetNext(handler2)

با نمونه‌گیری از مدیران خاص و تنظیم مدیر بعدی، یک زنجیره مسئولیت ساخته می‌شود.

4.6 مرحله پیاده‌سازی 4: کد مشتری

func main() {
    handler := &ConcreteHandler1{}

    // ساختن زنجیره مسئولیت
    handler.SetNext(&ConcreteHandler2{})

    // ارسال یک درخواست
    handler.HandleRequest(Request{Condition: true})
}

در کد مشتری، یک مدیر خاص نمونه‌گرفته می‌شود، مدیر بعدی تنظیم می‌شود و سپس متد HandleRequest فراخوانی می‌شود تا یک درخواست ارسال شود.