代码改变世界

C#面向对象设计模式纵横谈 笔记15 Command 命令(行为型模式)

2011-09-10 00:09  lujiao_cs  阅读(386)  评论(0编辑  收藏  举报

耦合与变化

耦合是软件不能抵御变化灾难的根本性原因。不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系。

动机(Motivation

   在软件构建过程中,行为请求者行为实现者” 通常呈现一种紧耦合。但在某些场合—— 比如需要对行为进行记录、撤销/重做(undo/redo)、事务等处理,这种无法抵御变化的紧耦合是不合适的。

   在这种情况下,如何将行为请求者行为实现者解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。“直接依赖”——>间接依赖”

意图(Intent

将一个请求封装为一个对象,从而使你可用不同的请求对客户行为的请求者进行参数化;对请求排队或记录请求日志, 以及支持可撤销的操作。   ——  《设计模式》GoF

例说Command应用  Codes in .NET

1)Document 类

    /// <summary>
    /// 已经存在的文件处理类
    /// </summary>
    public class Document
    {
        public virtual void ShowText()
        {
            //...........
        }
    }

2Graphics 

 /// <summary>
/// 已经存在的图像处理类
/// </summary>
public class Graphics
{
        public virtual void ShowGraphics()
        {
            //...........
        }
 }

3)ICommand 接口

    /// <summary>
    /// 可以写为接口或者抽象类
    /// 一般不包括默认的实现
    /// </summary>
    public interface ICommand
    {
       public void Show();
       public void Undo();
       public void Redo();
    }

4) DocumentCommand 

    /// <summary>
    /// 具体的命令对象 -- 从抽象意义来讲,DocumentCommand表示一个行为对象
    /// </summary>
    class DocumentCommand : ICommand
    {
        public Document _doc { get; set; }

        public DocumentCommand(Document doc)
        {
            this._doc = doc;
        }

        public void Show()
        {
            _doc.ShowText();
        }

        public void Undo()
        {
            //Document 对应的逻辑
        }
        public void Redo()
        {
            //Document 对应的逻辑
        }
    }

5) GraphicsCommand 

    /// <summary>
    /// 具体的命令对象 -- GraphicsCommand表示一个行为对象
    /// </summary>
    class GraphicsCommand : ICommand
    { 
        public Graphics _graphics;
        public GraphicsCommand(Graphics graphics)
        {
            this._graphics = graphics;
        }

        public void Show()
        {
            //..........
        }

        public void Undo()
        {
            //..........
        }

        public void Redo()
        {
            //...........
        }
    }

6)应用程序主干

    /// <summary>
    /// 应用程序主干(高层抽象),间接依赖具体的实现
    /// </summary>
    class Application
    {
        Stack<ICommand> stack;
        Stack<ICommand> undoList;

        /// <summary>
        /// 存储实现了ICommand接口的对象
        /// </summary>
        List<ICommand> list;

        public void Show()
        {
            foreach (ICommand item in list)
            {
                item.Show();
            }
        }

        public void Undo()
        {
            if (stack.Count != 0)
            {
                ICommand command = stack.Pop();
                command.Undo();
                undoList.Push(command);
            }

        }
        public void Redo()
        {
            if (undoList.Count != 0)
            {
                ICommand command = undoList.Pop();
                command.Redo();
            }
        }
    }

 

结构(Structure

 

 

 

 

 

 

 

 

 

 

 

 


 

Command模式的几个要点

1) Command模式的根本目的在于将行为请求者行为实现者” 解耦,在面向对象语言中,常见的实现手段是将行为抽象为对象

2) 实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息。 

3) 通过使用Composite模式,可以将多个命令封装为一个复合命令” MacroCommand。 

4) Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的接口-实现来定义行为接口规范,更严格,更符合抽象原则;Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱。函数指针抽象为了可被调用的对象,但是其和面向对象的抽象有差别。


推荐资源

1)《设计模式:可复用面向对象软件的基础》GoF

2)《面向对象分析与设计》Grady Booch 

3)《敏捷软件开发:原则、模式与实践》Robert C. Martin 

4)《重构:改善既有代码的设计》Martin Fowler 

5)Refactoring to PatternsJoshua Kerievsky