设计模式---命令模式



Command:
        定义命令的接口,声明执行的方法。
ConcreteCommand:
       具体的命令, 实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
        接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
        要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
        创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

这里采用从实例到定义,倒着描述的方式,先从实例入手,有个大致印象,有助于理解。

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。

分析:帅哥顾客,土豪订单,美女服务员,资深大厨的角色是什么?

帅哥顾客:Client

土豪订单:实现Command接口的具体Command

美女服务员:Invoker

资深大厨:Receiver

代码实现:

Command接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    /// <summary>
    /// Command为所有命令声明一个接口,调用命令对象的excute方法
    /// 就可以让接收者进行相关的动作,
    /// </summary>
    public abstract class Command
    {
        public abstract void Execute();
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    /// <summary>
    /// 具体的命令
    /// </summary>
    public class OrderCommand : Command
    {
        /// <summary>
        ///持有接受者对象
        /// </summary>
        SeniorChef receiver;
        Order order;
        public OrderCommand(SeniorChef receiver, Order order)
        {
            this.receiver = receiver;
            this.order = order;
        }
        public override void Execute()
        {
        
            Console.WriteLine("{0}桌的订单:", order.DiningTable);
            foreach (string item in order.FoodDic.Keys)
            {
                //通常会转调接收者对象的相应方法,让接收者来真正执行功能
                receiver.MakeFood(order.FoodDic[item],item);
            }
            Thread.Sleep(2000);//停顿一下 模拟做饭的过程

            Console.WriteLine("{0}桌的饭弄好了", order.DiningTable);
        }
    }
}

Waitor:Invoker调用者,seniorChef:接收者 厨师类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    /// <summary>
    /// 美女服务员类 这里作为调用者Invoker的角色
    /// </summary>
    public class Waitor
    {
        ArrayList commands = null;//可以持有很多的命令对象
        public Waitor()
        {
            commands = new ArrayList();
        }
        public void SetCommand(Command cmd)
        {
            commands.Add(cmd);
        }
        /// <summary>
        /// 提交订单 喊 订单来了,厨师开始执行
        /// </summary>
        public void OrderUp()
        {
            Console.WriteLine("美女服务员:叮咚,大厨,新订单来了.......");
            Console.WriteLine("资深厨师:收到");
            for (int i = 0; i < commands.Count; i++)
            {
                Command cmd = commands[i] as Command;
                if (cmd != null)
                {
                    cmd.Execute();
                }
            }
        }
    }
}

Waitor

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    /// <summary>
    /// 资深大厨类 是命令的Receiver
    /// </summary>
    public class SeniorChef
    {
        public void MakeFood(int num,string foodName)
        {
            Console.WriteLine("{0}份{1}", num,foodName);
        }
    }
}

SeniorChef

订单Order,封装订单内容,然后传入OrderCommand,将订单对象变为命令对象

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    /// <summary>
    /// 订单
    /// </summary>
    public class Order
    {
        /// <summary>
        /// 餐桌号码
        /// </summary>
        public int DiningTable { set; get; }
        /// <summary>
        /// food  key:饭名 value:多少份
        /// </summary>
        public Dictionary<string, int> FoodDic { set; get; }
    }
}

Order

测试端Program相当于Client角色

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.命令模式
{
    class Program
    {
        static void Main(string[] args)
        {
            //program类 作为客户端
            //创建2个order
            Order order1 = new Order();
            order1.DiningTable = 1;
            order1.FoodDic = new Dictionary<string, int>() ;
            order1.FoodDic.Add("西红柿鸡蛋面",1);
            order1.FoodDic.Add("小杯可乐",2);
          
            Order order2 = new Order();
            order2.DiningTable = 3;
            order2.FoodDic = new Dictionary<string, int>();
            order2.FoodDic.Add("尖椒肉丝盖饭", 1);
            order2.FoodDic.Add("小杯雪碧", 1);
            //创建接收者
            SeniorChef receiver=new SeniorChef();
            //将订单这个两个消息封装成命令对象
            OrderCommand cmd1 = new OrderCommand(receiver, order1);
            OrderCommand cmd2 = new OrderCommand(receiver, order2);
            //创建调用者 waitor
            Waitor invoker = new Waitor();
            //添加命令
            invoker.SetCommand(cmd1);
            invoker.SetCommand(cmd2);
            //将订单带到柜台 并向厨师喊 订单来了
            invoker.OrderUp();
            Console.Read();
        }
    }
}

测试结果:

命令模式优点:

1.降低对象之间的耦合度。
2.新的命令可以很容易地加入到系统中。
3.可以比较容易地设计一个组合命令。
4.调用同一方法实现不同的功能

缺点:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

适用环境:

1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起,即支持宏命令。








猜你喜欢

转载自blog.csdn.net/qq_40182703/article/details/80616893