命令模式再学习

   以前也写过设计模式,总是罗列一些自己都看不懂的话。一直都认为要想对设计模式有很好的理解,离不了实践的经验和不断的学习总结。这次是结合自己的理解并且本着通俗易懂的原则来写,适合入门级学习的人。

   有这么一种情况:在vs中。新建一个cs项目,按下F5运行,出现了一个窗体;又新建了一个bs项目,同样按下F5,这时运行时出现的是浏览器的页面。问题来了,在不同的应用环境下,按下同一个按钮,却出现了不同的运行结果。如果你是开发人员,你会如何实现?

   最糟糕的设计也不过是每一个动作都重新实现一遍,但是你想一想,vs中有多少这样的功能,如果要是一个一个的实现,那多麻烦,维护起来更是可怕。针对于这样的一种情况,可以使用命令模式。我们都知道所有的设计模式无非就是为了解耦,命令模式是怎么解耦的?适合在哪些情况下使用?

   命令模式的核心在于将动作的请求者从动作的执行者中解耦。先看一张类图:


   这是《大话设计模式》中讲烤羊肉串的例子的类图。就以它来讲:以前是客户端和烤肉串者紧密耦合,为了解耦在两者之间加入了”第三者”---服务员类和命令类。客户端持有服务员的引用,通过设置命令方法发出请求。通过通知执行方法告诉命令类去执行。而命令类和烤肉串类对动作的执行进行了封装,通过服务员传入不同参数,决定具体使用哪个命令,然后直接执行命令。这样就实现了动作的请求和动作的执行的分离。

 

这样解耦后有什么好处?

1. 如果另外需要几串烤牛板筋的话,就不需要修改类,直接在添加烤牛板筋类来继承命令类。(开闭原则:对扩展是开放的,对修改是关闭)

2. 另外一个重要的点在服务员类上。设置命令。可以较容易地设计一个命令队列,在需要的情况下,可以将命令记入日志。要怎么做?当我们执行命令的时候,将历史记录存储在磁盘上,一但系统死机,就可以将命令对象重新加载,并依次调用这些对象的execute方法。

3. 可以容易地实现redo 和 undo 操作。

 

应用命令模式的具体实例实现redo 和 undo 操作。C#的控制台程序模拟:

Calculator相当于烤肉串者

/*
 *创建人:王雅瑾
 *创建日期:2014/7/31 11:01:43
 *说明:
 *版权所有:
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Calculator
{
    class Calculator
    {
        private int _curr = 0;
        public void Operation(char @operator, int operand)
        {
            switch (@operator)
            {
                case '+': _curr += operand; break;
                case '-': _curr -= operand; break;
                case '*': _curr *= operand; break;
                case '/': _curr /= operand; break;
            }
            Console.WriteLine("Current value = {0,3} (following {1} {2})",
          _curr, @operator, operand);
        }
    }
}

Command相当于命令

/*
 *创建人:王雅瑾
 *创建日期:2014/7/31 10:47:24
 *说明:
 *版权所有:
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Calculator
{
    abstract  class Command
    {
        public abstract void Execute();
        public abstract void UnExecute();
    }

    class CalculatorCommand : Command
    {
        private char _operator;
        private int _operand;
        private Calculator _calculator;

        public CalculatorCommand(Calculator calculator, char @operator, int operand)
        {
            this._calculator = calculator;
            this._operator = @operator;
            this._operand = operand;
        }

        public char Operator
        {
            set { _operator = value; }
        }

        public int Operand
        {
            set { _operand = value; }
        }

        public override void Execute()
        {
            _calculator.Operation(_operator ,_operand );
        }

        public override void UnExecute()
        {
            _calculator.Operation(Undo(_operator), _operand);
        }

        private char Undo(char @operator)
        {
            switch (@operator)
            {
                case '+': return '-';
                case '-':  return '+';
                case '*':  return '/';
                case '/':  return '*';
                default: throw new ArgumentException("@operator");
            }
        }
    }
}

User相当于是服务员

/*
 *创建人:王雅瑾
 *创建日期:2014/7/31 11:10:33
 *说明:
 *版权所有:
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Calculator
{
    class User
    {
        private Calculator _calculator = new Calculator();
        private List<Command> _commands = new List<Command>();
        private int _current = 0;
        public void Redo(int levels){
            Console.WriteLine("\n---- Redo {0} levels ", levels);
            for (int i = 0; i < levels; i++)
            {
                if (_current < _commands.Count  )
                {
                    Command command = _commands[_current++];
                    command.Execute();
                }
            }
        }

        public void Undo(int levels)
        {
            Console.WriteLine("\n---- Undo {0} levels ", levels);
            for (int i = 0; i < levels; i++)
            {
                if (_current > 0)
                {
                    Command command = _commands[--_current] as Command;
                    command.UnExecute();
                }
            }
        }
        public void Compute(char @operator, int operand)
        {
            Command command = new CalculatorCommand(_calculator ,@operator,operand);
            command.Execute();
            _commands.Add(command);
            _current++;
        }
    }
}

Program相当于客户端类

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

namespace Calculator
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User();
            user.Compute('+', 100);
            user.Compute('-', 50);
            user.Compute('*', 10);
            user.Compute('/', 2);

            user.Undo(4);

            user.Redo(4);
            Console.ReadKey();
        }
    }
}

思考:命令模式和组合模式一起实现宏命令类

     命令模式和备忘录模式一起撤退和重做的操作。

 

总结:有了理论之后多加实践才能真正理解设计模式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值