设计模式(14)命令模式

模式介绍

命令模式将请求封装为对象,从而允许开发人员根据接收到该命令的类来不同地对待该请求。此外,它能够实现更复杂的体系结构,甚至可以实现诸如撤销/重做之类的操作。

责任链模式非常适合命令模式,因为前者可以使用后者的对象来表示其请求。

示例

我们将建模一个系统,在该系统中,我们可以在快餐店创建订单,并使用命令模式进行订单添加、删除和修改。

菜单:

/// <summary>
/// Represents an item being ordered from this restaurant.
/// </summary>
public class MenuItem
{
    public string Name { get; set; }
    public int Amount { get; set; }
    public double Price { get; set; }

    public MenuItem(string name, int amount, double price)
    {
        Name = name;
        Amount = amount;
        Price = price;
    }

    public void Display()
    {
        Console.WriteLine("
Name: " + Name);
        Console.WriteLine("Amount: " + Amount.ToString());
        Console.WriteLine("Price: $" + Price.ToString());
    }
}

顾客:

/// <summary>
/// The Invoker class
/// </summary>
public class Patron
{
    private OrderCommand _orderCommand;
    private MenuItem _menuItem;
    private FastFoodOrder _order;

    public Patron()
    {
        _order = new FastFoodOrder();
    }

    public void SetCommand(int commandOption)
    {
        _orderCommand = new CommandFactory().GetCommand(commandOption);
    }

    public void SetMenuItem(MenuItem item)
    {
        _menuItem = item;
    }

    public void ExecuteCommand()
    {
        _order.ExecuteCommand(_orderCommand, _menuItem);
    }

    public void ShowCurrentOrder()
    {
        _order.ShowCurrentItems();
    }
}

public class CommandFactory
{
    //Factory method
    public OrderCommand GetCommand(int commandOption)
    {
        switch (commandOption)
        {
            case 1:
                return new AddCommand();
            case 2:
                return new ModifyCommand();
            case 3:
                return new RemoveCommand();
            default:
                return new AddCommand();
        }
    }
}

抽象的命令类:

/// <summary>
/// The Command abstract class
/// </summary>
public abstract class OrderCommand
{
    public abstract void Execute(List<MenuItem> order, MenuItem newItem);
}

具体的命令类:

/// <summary>
/// A concrete command
/// </summary>
public class AddCommand : OrderCommand
{
    public override void Execute(List<MenuItem> currentItems, MenuItem newItem)
    {
        currentItems.Add(newItem);
    }
}

/// <summary>
/// A concrete command
/// </summary>
public class RemoveCommand : OrderCommand
{
    public override void Execute(List<MenuItem> currentItems, MenuItem newItem)
    {
        currentItems.Remove(currentItems.Where(x=>x.Name == newItem.Name).First());
    }
}

/// <summary>
/// A concrete command
/// </summary>
public class ModifyCommand : OrderCommand
{
    public override void Execute(List<MenuItem> currentItems, MenuItem newItem)
    {
        var item = currentItems.Where(x => x.Name == newItem.Name).First();
        item.Price = newItem.Price;
        item.Amount = newItem.Amount;
    }
}

客户端调用:

static void Main(string[] args)
{
    Patron patron = new Patron();
    patron.SetCommand(1 /*Add*/);
    patron.SetMenuItem(new MenuItem("French Fries", 2, 1.99));
    patron.ExecuteCommand();

    patron.SetCommand(1 /*Add*/);
    patron.SetMenuItem(new MenuItem("Hamburger", 2, 2.59));
    patron.ExecuteCommand();

    patron.SetCommand(1 /*Add*/);
    patron.SetMenuItem(new MenuItem("Drink", 2, 1.19));
    patron.ExecuteCommand();

    patron.ShowCurrentOrder();

    //Remove the french fries
    patron.SetCommand(3 /*Remove*/);
    patron.SetMenuItem(new MenuItem("French Fries", 2, 1.99));
    patron.ExecuteCommand();

    patron.ShowCurrentOrder();

    //Now we want 4 hamburgers rather than 2
    patron.SetCommand(2 /*Edit*/);
    patron.SetMenuItem(new MenuItem("Hamburger", 4, 2.59));
    patron.ExecuteCommand();

    patron.ShowCurrentOrder();

    Console.ReadKey();
}

总结

命令设计模式试图将命令封装为对象,并允许不同的接收器根据接收器自己的设计来处理它们。

源代码

https://github.com/exceptionnotfound/DesignPatterns/tree/master/Command

原文

https://www.exceptionnotfound.net/command-the-daily-design-pattern/