《Head First设计模式》第六章笔记-命令模式

封装调用-命令模式

 

命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。

本篇中将不再描述书中所引入的“巴斯特家电自动化公司”的遥控器控制案例,而使用简单易懂的餐厅案例。

在开始之前,让我们通过一个现实中的例子来了解命令模式。

理解命令模式

让我们回到餐厅,研究顾客、女招待、订单,以及快餐厨师之间的交互。通过这样的互动,你将体会到命令模式所涉及的对象,也会知道它们之间如何被解耦。

将以上流程代入到编程的对象中进一步思考对象与方法之间的关系:

分析餐厅对应的角色与职责

1、顾客:发出请求的对象。
2、订单:封装了准备餐点的请求。
3、女招待:接收订单,然后调用订单的orderUp方法,将订单提交到柜台,无需知道订单细节。
4、厨师:收到订单后,按订单实现对应餐点的所有方法制作餐点。

从餐厅到命令模式

命令模式类图

  • Command:定义命令的接口,声明执行的方法。
  • ConcreteCommand: 具体的命令, 实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
  • Receiver:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
  • Client: 创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

命令模式定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。

实现命令接口:

1

2

3

public abstract class Command{

    public abstract void Execute();

}

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class OrderCommand implements Command{

    //持有接受者对象

    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(2000);//停顿一下 模拟做饭的过程

        Console.WriteLine("{0}桌的饭弄好了", order.DiningTable);

    }

}

Invoker调用者,seniorChef:接收者

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class Waiter{

    ArrayList commands = null;//可以持有很多的命令对象

    public Waiter(){

        commands = new ArrayList();

    }

    public void SetCommand(Command cmd){

        commands.Add(cmd);

    }

    //提交订单 喊 订单来了,厨师开始执行

    public void OrderUp(){

        Console.WriteLine("美女服务员:叮咚,大厨,新订单来了.......");

        Console.WriteLine("资深厨师:收到");

        for (int i = 0; i < commands.Count; i++){

            Command cmd = commands[i] as Command;

            if (cmd != null){

                cmd.Execute();

            }

        }

    }

}

1

2

3

4

5

public class SeniorChef{

    public void MakeFood(int num,string foodName){

        Console.WriteLine("{0}份{1}", num,foodName);

    }

}

订单Order,封装订单内容,然后传入OrderCommand,将订单对象变为命令对象

1

2

3

4

5

6

public class Order{

    // 餐桌号码

    public int DiningTable { set; get; }

    // food key:饭名 value:多少份

    public Dictionary FoodDic { set; get; }

}

测试端Program相当于Client角色

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

class Program{

    public static void main(string[] args){

    //program类 作为客户端

    //创建2个order

    Order order1 = new Order();

    order1.DiningTable = 1;

    order1.FoodDic = new Dictionary() ;

    order1.FoodDic.Add("西红柿鸡蛋面",1);

    order1.FoodDic.Add("小杯可乐",2);

    Order order2 = new Order();

    order2.DiningTable = 3;

    order2.FoodDic = new Dictionary();

    order2.FoodDic.Add("尖椒肉丝盖饭"1);

    order2.FoodDic.Add("小杯雪碧"1);

    //创建接收者

    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.系统需要将一组操作组合在一起,即支持宏命令。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂机器学习库graphLab

文章目录目录什么是graphlab为什么使用graphlab?如何安装graphlab?graphlab的简单使用。目录 什么是graphlab GraphLab 是由CMU&#xff08;卡内基梅隆大学&#xff09;的Select 实验室在2010 年提出的一个基于图像处理模型的开源图计算框架&#xff0c;框架使用C语言开发实…

《Head First设计模式》第七章-适配器模式、外观模式

适配器模式 适配器模式是什么&#xff0c;你一定不难理解&#xff0c;因为现实中到处都是。比如说&#xff1a; 如果你需要在欧洲国家使用美国制造的笔记本电脑&#xff0c;你可能需要使用一个交流电的适配器…… 当你不想改变现有的代码&#xff0c;解决接口不适配问题&#…

《Head First设计模式》第八章笔记-模板方法模式

模板方法模式 之前所学习的模式都是围绕着封装进行&#xff0c;如对象创建、方法调用、复杂接口的封装等&#xff0c;这次的模板方法模式将深入封装算法块&#xff0c;好让子类可以在任何时候都将自己挂接进运算里。 模板方法定义&#xff1a;模板方法模式在一个方法中定义一…

机器学习基础-吴恩达-coursera-(第一周学习笔记)----Introduction and Linear Regression

课程网址&#xff1a;https://www.coursera.org/learn/machine-learning Week 1 —— Introduction and Linear Regression 目录 Week 1 Introduction and Linear Regression目录一 介绍1-1 机器学习概念及应用1-2 机器学习分类 二 单变量的线性回归2-1 假设函数hypothesis2…

常见8种机器学习算法总结

简介 机器学习算法太多了&#xff0c;分类、回归、聚类、推荐、图像识别领域等等&#xff0c;要想找到一个合适算法真的不容易&#xff0c;所以在实际应用中&#xff0c;我们一般都是采用启发式学习方式来实验。通常最开始我们都会选择大家普遍认同的算法&#xff0c;诸如SVM&a…

redis——数据结构(字典、链表、字符串)

1 字符串 redis并未使用传统的c语言字符串表示&#xff0c;它自己构建了一种简单的动态字符串抽象类型。 在redis里&#xff0c;c语言字符串只会作为字符串字面量出现&#xff0c;用在无需修改的地方。 当需要一个可以被修改的字符串时&#xff0c;redis就会使用自己实现的S…

Hotspot虚拟机的对象

创建 Step1:类加载检查 虚拟机遇到一条 new 指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加载过程。 Step2:分…

redis——数据结构(整数集合,压缩列表)

4、整数集合 整数集合&#xff08;intset&#xff09;是 Redis 用于保存整数值的集合抽象数据结构&#xff0c; 可以保存 int16_t 、 int32_t 、 int64_t 的整数值&#xff0c; 并且保证集合中不会出现重复元素。 实现较为简单&#xff1a; typedef struct intset {// 编码方…

机器学习知识总结系列- 知识图谱(0-0)

文章目录目录机器学习知识图谱目录 本系列的文章只是根据个人的习惯进行总结&#xff0c;可能结构与一些书籍上不太一样&#xff0c;开始的内容比较简单&#xff0c;会随着后续的深入&#xff0c;不断丰富和更新图谱&#xff0c;同时也期待有相同兴趣的朋友一起给我留言一起丰富…

跳表介绍和实现

想慢慢的给大家自然的引入跳表。 想想&#xff0c;我们 1&#xff09;在有序数列里搜索一个数 2&#xff09;或者把一个数插入到正确的位置 都怎么做&#xff1f; 很简单吧 对于第一个操作&#xff0c;我们可以一个一个比较&#xff0c;在数组中我们可以二分&#xff0c;这…

机器学习知识总结系列- 基本概念(1-0)

文章目录目录1. 机器学习的定义2. 机器学习的分类2.1根据是否在人类监督下进行训练监督学习非监督学习半监督学习强化学习2.2根据是否可以动态渐进的学习在线学习批量学习2.3根据是否在训练数据过程中进行模式识别实例学习基于模型的学习3. 机器学习中的一些常见名词4. 机器学习…

剑指offer(刷题21-30)--c++,Python版本

文章目录目录第 21题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第22 题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第23 题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第24 题&#xff1a;解题思路&#xff1a;代码实现…

剑指offer(刷题41-50)--c++,Python版本

文章目录目录第41题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第42题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第43题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第44题&#xff1a;解题思路&#xff1a;代码实现&am…

redis——持久化

因为redis是内存数据库&#xff0c;他把数据都存在内存里&#xff0c;所以要想办法实现持久化功能。 RDB RDB持久化可以手动执行&#xff0c;也可以配置定期执行&#xff0c;可以把某个时间的数据状态保存到RDB文件中&#xff0c;反之&#xff0c;我们可以用RDB文件还原数据库…

剑指offer(刷题51-60)--c++,Python版本

文章目录目录第51题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第52题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第53题&#xff1a;解题思路&#xff1a;代码实现&#xff1a;cpython第54题&#xff1a;解题思路&#xff1a;代码实现&am…

2017第一届河北省大学生程序设计竞赛题解

超级密码 小明今年9岁了&#xff0c;最近迷上了设计密码&#xff01;今天&#xff0c;他又设计了一套他认为很复杂的密码&#xff0c;并且称之为“超级密码”. 说实话&#xff0c;这套所谓的“超级密码”其实并不难&#xff1a;对于一个给定的字符串&#xff0c;你只要提取其中…

大数的四则运算(加法、减法、乘法、除法)

大数的四则运算&#xff08;加法、减法、乘法、除法&#xff09; 前言&#xff1a; 在计算机中数字表示的范围是有限制的&#xff0c;比如我们熟知的 int、float、double 等数据类型所能表示的范围都是有限的&#xff0c;如果我们要对位数达到几十位、几百位、上千位的大整数进…

随机过程1

随机过程1概述1.参考书目2.主要内容3.概率论--基本概念回顾3.1对“不确定性”的认识3.2 应对“不确定性”应该怎么做3.3随机变量&#xff08;Random Variable&#xff09;3.4分布函数&#xff08;Distribution Function&#xff09;3.5概率密度&#xff08;Density&#xff09;…