系列文章

[Head First设计模式]山西面馆中的设计模式——装饰者模式

[Head First设计模式]山西面馆中的设计模式——观察者模式

[Head First设计模式]山西面馆中的设计模式——建造者模式

[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

[Head First设计模式]一个人的平安夜——单例模式

[Head First设计模式]抢票中的设计模式——代理模式

[Head First设计模式]面向对象的3特征5原则

[Head First设计模式]鸭子模型——策略模式

[Head First设计模式]云南米线馆中的设计模式——模版方法模式

实例

这里采用书中餐厅订餐的例子。餐厅订餐的例子还是比较简单的,也比较好理解,书中的遥控器的例子,太长了,能把人绕晕,图1:

图2:

从餐厅到命令模式

命令模式类图

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();
}
}

OrderCommand:具体的命令,继承自Command抽象类

 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();//停顿一下 模拟做饭的过程 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 = ; 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 = ;
order1.FoodDic = new Dictionary<string, int>() ;
order1.FoodDic.Add("西红柿鸡蛋面",);
order1.FoodDic.Add("小杯可乐",); Order order2 = new Order();
order2.DiningTable = ;
order2.FoodDic = new Dictionary<string, int>();
order2.FoodDic.Add("尖椒肉丝盖饭", );
order2.FoodDic.Add("小杯雪碧", );
//创建接收者
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.系统需要将一组操作组合在一起,即支持宏命令。

今天在家研究了一天命令模式,以上为个人理解,如有不妥之处,请指出,一起交流学习,谢谢。

参考:

Head first 设计模式

百度百科

[Head First设计模式]餐馆中的设计模式——命令模式的更多相关文章

  1. .NET设计模式(17):命令模式(Command Pattern)(转)

    概述 在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”.但在某些场合,比如要对行为进行“记录.撤销/重做.事务”等处理,这种无法抵御变化的紧耦合是不合适的.在这种情况下,如何将“行为 ...

  2. 设计模式之第14章-命令模式(Java实现)

    设计模式之第14章-命令模式(Java实现) “小明,滚出去.”“小明,这个问题怎么做?”(可怜的小明无奈躺枪.小明:老师,我和你有什么仇什么怨,我和你有什么仇什么怨啊到底...老师:小明,滚出去.习 ...

  3. [Android]GOF23种设计模式 & Android中的设计模式

    GOF23种设计模式 设计原则: 1. 单一职责原则(SRP):就一个类而言,应该仅有一个引起它变化的原因 2. 开放-封闭原则(OCP):软件实体(类.模块.函数等)应该可以扩展,但是不可修改.即对 ...

  4. [设计模式]JDK中的设计模式

    转载自:http://blog.csdn.net/gtuu0123/article/details/6114197 本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图. 首先来个总结,具体 ...

  5. C#设计模式学习笔记:(14)命令模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7873322.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第二个模式--命 ...

  6. 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...

  7. 设计模式总结篇系列:命令模式(Command)

    在程序设计中,经常会遇到一个对象需要调用另外一个对象的某个方法以达到某种目的,在此场景中,存在两个角色:请求发出者和请求接收者.发出者发出请求,接收者接收请求并进行相应处理.有时候,当需要对请求发出者 ...

  8. 【设计模式】行为型06命令模式(Command Pattern)

    命令模式 个人理解:命令模式,本质上是一种多层次的封装. 好处:降低耦合,扩展极其方便. 以下一段文案摘抄自:http://www.runoob.com/design-pattern/command- ...

  9. Java设计模式(学习整理)---命令模式

    设计模式之Command(学习整理) 1.Command定义 不少Command模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单选择一个命令时,然后会执行一些动作. 将这些命令封装 ...

随机推荐

  1. Mysql慢查询和慢查询日志分析

     Mysql慢查询和慢查询日志分析   众所周知,大访问量的情况下,可添加节点或改变架构可有效的缓解数据库压力,不过一切的原点,都是从单台mysql开始的.下面总结一些使用过或者研究过的经验,从配置以 ...

  2. 【2016-11-10】【坚持学习】【Day23】【Socket 编程初步了解】

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.

  3. NOIP模拟赛20161023

    题目名 双色球 魔方 czy的后宫 mex 源文件 ball.cpp/c/pas cube.cpp/c/pas harem.cpp/c/pas mex.cpp/c/pas 输入文件 ball.in c ...

  4. Freemarker与Springmvc

    1.导入springmvc和freemarker的jar包 2.web.xml中配置Spring和Springmvc <?xml version="1.0" encoding ...

  5. iPhone添加邮箱

    阿里云邮箱设置 手机自带的电子邮件客户端该如何添加阿里云邮账号呢?这里以iPhone4s和安卓系统为例,分别进行添加阿里云邮箱帐号的添加.   官网是这么介绍的:   一.如下以iPhone4s为例, ...

  6. JSP九大内置组件

    request:用户端请求,此请求会包含来自get/post请求的参数 response:网页传回用户端的回应 pagecontext:网页上下文,也就是网页的属性 session:与请求有关的会话期 ...

  7. CWMP开源代码研究3——ACS介绍

    声明:本文涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅号:408797506) 本文介绍自己用过的ACS,其中包括开源版(提供下载包)和商业版(仅提供安装包下载 ...

  8. js 检测页面刷新或关闭

    window.onbeforeunload=function(){ //要提交的内容 return "随意写";//必须有return ,不然只有ie有效,chrome无效 }

  9. bzoj 3163: [Heoi2013]Eden的新背包问题

    Description "寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心心静,能不能说给我听."失忆的Eden总想努力地回忆起过去,然而总是只能清晰地记得那种思念的 ...

  10. 【jQuery】 jQuery上下飘动效果

    jQuery实现图片上下飘动效果 function moveRocket() { $(".smallShip") //2000毫秒内top = top + 60: .animate ...