命令模式

使用命令模式,对于undo机制。

封装一个请求作为一个对象,让你参数化客户端,对于不同的请求,队列或者日志请求,并且支持可撤销操作。

这个模式最大的优势就是,它解耦了调用操作的对象,从一个如何知道它如何执行的对象。

开发一个简单的Notepad克隆。

第一步,我们想去创建一个抽象,围绕我们的textbox控件。在命令模式,这个抽象叫做接收者。
接收者在我们的例子中是一个对象,叫做Document。

class Document
{
	private TextBox textbox;
	
	public Document(TextBox textbox)
	{
		this.textbox = textbox;
	}
	
	public void BoldSelection()
	{
		Text = String.Format("<b>{0}<b>", Text);
	}
	
	    public void UnderlineSelection()
    {
        Text = String.Format("<u>{0}</u>", Text);
    }

    public void ItalicizeSelection()
    {
        Text = String.Format("<i>{0}</i>", Text);
    }

    public void Cut()
    {
        textbox.Cut();
    }

    public void Copy()
    {
        textbox.Copy();
    }

    public void Paste()
    {
        textbox.Paste();
    }

    public string Text
    {
        get { return textbox.Text; }
        set { textbox.Text = value; }
    }
}

黑体选择,下划线选择,斜体(Italicize)选择。

我们已经定义于Document对象的,是一些操作,可以于document执行,完整地解耦这个功能从我么的应用。
如果我们想要改变加粗选定内容时所发生的情况,我们会转到这个对象,而不是转到表示代码。

第二步,我们将需要去设计我们的命令接口。自从可能,我们有一些命令不需要undo机制(例如,Copy),我们已经创建两个基类(Command和UndoableCommand)。我们将在本文的后面看一下UndoableCommand是如何连接的。目前,只要记住,这是一个类,去派生,如果你需要你的命令能够undo它自己。

public abstract class Command
{
    public abstract void Execute();
}

public abstract class UndoableCommand : Command
{
    public abstract void Undo();
}

为了处理粗体,我们将创建如下的代码:

class BoldCommand : UndoableCommand
{
    private Document document;
    private string previousText;
    public BoldCommand(Document doc)
    {
        this.document = doc;
        previousText = this.document.Text;
    }

    public override void Execute()
    {
        document.BoldSelection();
    }

    public override void Undo()
    {
        document.Text = previousText;
    }
}

通过创建一个document对象,包裹文本盒子,我们能够完整地解耦对象,它将调用操作(一个菜单项)从一个如何知道执行(document object)解耦。

剩下的命令对象非常类似于上面。

剩下的代码,我们将需要去带来所有的事物在一起,是一个CommandManager。CommandManager是一个非常简单的类,
它有一个内部的栈,持续追踪我们的命令对于我们的undo机制。

class CommandManager
{
    private Stack commandStack = new Stack();

    public void ExecuteCommand(Command cmd)
    {
        cmd.Execute();
        if (cmd is UndoableCommand)
        {
            commandStack.Push(cmd);
        }
    }


    public void Undo()
    {
        if (commandStack.Count > 0)
        {
            UndoableCommand cmd = (UndoableCommand)commandStack.Pop();
            cmd.Undo();
        }
    }
} 

我们看上面的代码,我们只需要去添加命令到undo栈,如果它是一个UndoableCommand。