اخبار، مطالب و رویدادهای مرتبط با توسعه نرم افزار رادکام

الگوی طراحی Command

الگوی Command یکی از الگوهای رفتاری می باشد. این الگو برای ارتباط بین اشیا به کار برده می شود. به صورتی که درخواست ها در یک شی سازمان دهی می شوند. این الگو کار را برای کنترل های دستوری راحت تر می کند. الگوی Command یک الگوی رفتاری است. همان طور که گفته شد الگوهای رفتاری جهت ارتباط اشیا با یکدیگر استفاده می شوند. به این صورت که تقاضاها در این نوع الگو در یک شی سازمان دهی می شوند و به همین دلیل می توان آن ها را به راحتی در فعالیت ها استفاده نمود و سازمان دهی و کنترل دستورات آسان تر خواهد شد.

کاربردهای الگوی طراحی Command

خاصیت الگوی Command باعث شده است که کاربردهای مختلفی از جمله موارد زیر را داشته باشد:

  • برای برنامه ای که شامل Undo و Redo است استفاده می شود و یکی از بهترین الگوها برای پیاده سازی فرامین منو ویرایش می باشد.
  • می تواند درخواست ها را به گیرنده های مختلف ارسال کند لذا برای ارسال درخواست ها به گیرنده های مختلف می توان از آن استفاده نمود.
  • برای صف بندی و همچنین تهیه Log از درخواست های دریافت شده و یا رد درخواست ها به کار برده می شود زیرا درخواست ها را می توان از طریق یک شی مرتب و سازمان دهی نمود.
  • امکان ایجاد تراکنش های سطح بالا با استفاده از اعمال سطح پایین را فراهم می کند.
  •  

نمودار کلاس دیاگرام الگوی طراحی Command

Command Pattern Diagram

همان طور که در دیاگرام مشخص است نمودار کلاس الگوی Command شامل کلاس های زیر است:

  • کلاس Client یا مشتری: این کلاس شخصی را نشان می دهد که می خواهد از این الگو استفاده و یا فعالیتی را آغاز نماید.
  • کلاس Receiver یا دریافت کننده: دارای یک متد عمومی به نام action است. این کلاس در اصل دریافت کننده فرمان Command است. توسط ارتباطی که با کلاس Concrete Command دارد می تواند با کلاس Command ارتباط برقرار کند. الگویتم ها نیز در این کلاس مشخص می شوند.
  • کلاس Command: این کلاس مجرد بوده و یک متد عمومی به نام execute دارد و بقیه از آن ارث بری می کنند. می توان توسط Interface آن را پیاده سازی نمود. پارامترهایی که برای اجرا شدن لازم است در این کلاس تعریف می شود.
  • کلاس Invoker: زمان اجرای برنامه را مشخص می کند، این که فرمان بلافاصله اجرا شود یا یک صف برای آن درنظر گرفته شود. می توان آن را به عنوان مخزنی از فرامین در نظر گرفت.

در ادامه ، پیاده سازی این الگو را در یک مثال توضیح می دهیم:

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

برای استفاده از الگوی Command برای پیاده سازی محاسبه قیمت محصولات در صندوق می توان کلاس مشتری را به صورت زیر تعریف نمود که در آن یک لیست از محصولات تعریف شده و بر روی آن دو عمل کاهش قیمت بر اثر تخفیف و افزایش قیمت بر اثر مالیات انجام می شود:


    class Program
    {
        static void Main(string[] args)
        {
            var modifyPrice = new ModifyPrice();
            var product = new Product("Phone", 500);

            #region Execute Queue commands for product price

            var commandList = new List();
            commandList.Add(new ProductCommand(product, PriceAction.Decrease, product.Price * 20 / 100));
            commandList.Add(new ProductCommand(product, PriceAction.Increase, product.Price * 9 / 100));

            ExecuteList(product, modifyPrice, commandList);

            Console.WriteLine(product);
            Console.WriteLine();

            modifyPrice.UndoActions();
            Console.WriteLine(product);

            #endregion

            string line = Console.ReadLine();
        }

        private static void Execute(Product product, ModifyPrice modifyPrice, ICommand productCommand)
        {
            modifyPrice.SetCommand(productCommand);
            modifyPrice.Invoke();
        }


        private static void ExecuteList(Product product, ModifyPrice modifyPrice, List productCommand)
        {
            foreach (var item in productCommand)
            {
                modifyPrice.SetCommand(item);
                modifyPrice.Invoke();
            }
        }
    }

کلاس دریافت کننده نیز به صورت زیر تعریف می شود که در آن الگوریتم ها و متدهای مورد استفاده تعریف می شود:


    class Product
    {
        public string Name { get; set; }
        public int Price { get; set; }

        public Product(string name, int price)
        {
            Name = name;
            Price = price;
        }

        public void IncreasePrice(int amount)
        {
            Price += amount;
            Console.WriteLine($"The price for the {Name} has been increased by {amount}$.");
        }

        public bool DecreasePrice(int amount)
        {
            if (amount < Price)
            {
                Price -= amount;
                Console.WriteLine($"The price for the {Name} has been decreased by {amount}$.");
                return true;
            }
            else
            {
                //Console.WriteLine($"The price for the {Name} has not changed.");
                return false;
            }
        }

        public override string ToString() => $"Current price for the {Name} product is {Price}$.";
    }

کلاس Command کلاسی مجرد است که دستورات مورد نیاز و پارامترها در آن تعریف می شود:


    public interface ICommand
    {
        void ExecuteAction();
        void UndoAction();
    }

و در کلاس Concrete Command دستورات تعریف شده به صورت زیر پیاده سازی می شوند:


    class ProductCommand : ICommand
    {
        private readonly Product _product;
        private readonly PriceAction _priceAction;
        private readonly int _amount;

        public bool IsCommandExecuted { get; private set; }

        public ProductCommand(Product product, PriceAction priceAction, int amount)
        {
            _product = product;
            _priceAction = priceAction;
            _amount = amount;
        }

        public void ExecuteAction()
        {
            if (_priceAction == PriceAction.Increase)
            {
                _product.IncreasePrice(_amount);
                IsCommandExecuted = true;
            }
            else
            {
                IsCommandExecuted = _product.DecreasePrice(_amount);
            }
        }

        public void UndoAction()
        {
            if (!IsCommandExecuted)
                return;

            if (_priceAction == PriceAction.Increase)
            {
                _product.DecreasePrice(_amount);
            }
            else
            {
                _product.IncreasePrice(_amount);
            }
        }
    }

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


class ModifyPrice
    {
        private readonly List _commands;
        private ICommand _command;

        public ModifyPrice()
        {
            _commands = new List();
        }

        public void SetCommand(ICommand command) => _command = command;

        public void Invoke()
        {
            _commands.Add(_command);
            _command.ExecuteAction();
        }

        public void UndoActions()
        {
            foreach (var command in Enumerable.Reverse(_commands))
            {
                command.UndoAction();
            }
        }
    }

پست های مرتبط

نام را وارد کنید
تعداد کاراکتر باقیمانده: 1000
نظر خود را وارد کنید