الگوهای طراحی - Chain of Responsibility

سه شنبه 21 بهمن 1399

این الگوی تحت الگوی رفتاری قرار می گیرد. اهدافی که الگوی Chain of Responsibility آن ها را دنبال می کند عبارتند از: 1. انجام کار در چند مرحله 2 . حذف پیچیدگی های پیاده سازی در مواردی که با if و else های تو در تو روبرو می شویم می توانیم از این الگو استفاده کنیم. در این مقاله مثال انتقال پول را بررسی خواهیم کرد.

الگوهای طراحی - Chain of Responsibility

ما یکسری دیتا داریم که به عنوان ورودی دریافت می کنیم که در واقع دیتای context ما می باشد و آن ها را در یک کلاس قرار می دهیم. و یک کلاس داریم که یک متد processor دارد و یک property از جنس خودش دارد که به نفر بعدی اشاره می کند که successor ما می باشد. حالا به جای استفاده از if، به ازای هر if یک کلاس درست می کنیم.

در این مثال من یک کلاس Customer را در نظر می گیرم که موجودی حساب، وضعیت فعال بودن، میزان برداشت روزانه و پسورد را شامل می شود.

public class Customer
{
            public int AccountValue { get; set; }
            public bool IsActive { get; set; }
            public int MaxDateValue { get; set; }
            public string Password { get; set; }
}

صحبت از یک context data کردیم که دیتای ورودی من را تشکیل می دهد.

با فرض اینکه مشتری را از دیتابیس خوانده ایم و می دانیم کیست، پسورد و مبلغی که قصد انتقال دارد و همچنین مشتری انتقال دهنده و گیرنده را در ورودی دریافت می کنیم.

public class RequestContext
{
            public string Password { get; set; }
            public int Value { get; set; }
            public Customer FromCustomer { get; set; }
            public Customer ToCustomer { get; set; }
}

باید روالی ایجاد کنیم که بتوانیم دیتای ورودی را دریافت کنیم، شروع به proccess کنیم و نتیجه خروجی را بدهیم.

برای دیتای خروجی نیز یک کلاس در نظر می گیریم که در اینجا فقط یک پیام برمی گرداند.

public class ResponseContext
{
            public string Message { get; set; }
}

کارهایی که تا اینجا کردیم ممکن است شما را یاد http بیاندازد که یه request می گیرد و یک response برمی گرداند.

صحبت از یک کلاس کردیم که متدی برای محاسبه و property از جنس خودش در نقش successor دارد.

public abstract class TransferMoney
{
            protected readonly TransferMoney _successor;
            public TransferMoney(TransferMoney successor)
            {
                _successor = successor;
            }
            public abstract ResponseContext Execute(RequestContext requestContext);
}

حالا شروع به impelement کردن مراحل می کنیم.

برای شروع بررسی کردن پسورد را می نویسیم.

public class CheckPassword : TransferMoney
{
            public CheckPassword(TransferMoney successor) : base(successor)
            {
            }
            public override ResponseContext Execute(RequestContext requestContext)
            {
                if(requestContext.FromCustomer.Password == requestContext.Password)
                {
                    return (_successor.Execute(requestContext));
               }
               else
               {
                   return (new ResponseContext()
                   {
                       Message = "incorrect password",
                   });
                }
            }
}

کلاس بعدی بررسی می کنیم که آیا موجودی کافی می باشد یا خیر.

public class CheckValue : TransferMoney
{
            public CheckValue(TransferMoney successor) : base(successor)
            {
            }
            public override ResponseContext Execute(RequestContext requestContext)
            {
                if (requestContext.FromCustomer.AccountValue >= requestContext.Value)
                {
                    return (_successor.Execute(requestContext));
                }
                else
                {
                    return (new ResponseContext()
                    {
                        Message = "Invalid Value",
                    });
                }
            }
}

مرحله بعدی بررسی کردن فعال بودن مشتری می باشد:

public class CheckActive : TransferMoney
{
            public CheckActive(TransferMoney successor) : base(successor)
            {
            }
            public override ResponseContext Execute(RequestContext requestContext)
            {
                if (requestContext.FromCustomer.IsActive)
                {
                    return (_successor.Execute(requestContext));
                }
                else
                {
                    return (new ResponseContext()
                    {
                       Message = "Acount Is Inactive",
                    });
                }
            }
}

و در نهایت انتقال پول:

public class FinalTransfer : TransferMoney
{
            public FinalTransfer(TransferMoney successor) : base(successor)
            {
            }
            public override ResponseContext Execute(RequestContext requestContext)
            {
               requestContext.FromCustomer.AccountValue -= requestContext.Value;
               requestContext.FromCustomer.AccountValue += requestContext.Value;
               return (new ResponseContext()
                {
                    Message = "Transfer Complete"
                });
            }
}

براحتی میتوانیم ترتیب های متفاوت از این کلاس ها ایجاد کنیم. برای انتقال پول با فرض اینکه مشتریان را از بانک خوانده باشیم:

Customer fromCustomer = new Customer()
{
                AccountValue = 1000,
                IsActive = true,
                MaxDateValue = 100,
                Password = "1234",
};
Customer toCustomer = new Customer()
{
                AccountValue = 10000,
                IsActive = true,
                MaxDateValue = 2000,
                Password = "1234",
};
var transfer = new CheckPassword(new CheckValue(new CheckValue(new FinalTransfer(null))));
transfer.Execute(new RequestContext()
            {
                 FromCustomer = fromCustomer,
                 ToCustomer = toCustomer,
                 Password = "1234",
                 Value = 150,
            });

حالا می توانیم براحتی ترتیب ها را عوض کنیم یعنی اول موجودی را بررسی کنیم و سپس فعال بودن را بررسی کنیم.

کم و زیاد کردن یا جابجایی مراحل براحتی انجام می شود و اگر یک مرحله بخواهیم اضافه کنیم کد های قبلی تغییری نمی کند.

پایان

محسن فرخی

نویسنده 2 مقاله در برنامه نویسان
  • C#.net
  • 2k بازدید
  • 2 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید

نظرات کاربران

برای درج نظر باید وارد سایت شوید