第二十三章烤羊肉串引来的思考--命令模式(读书笔记)

本文主要是介绍第二十三章烤羊肉串引来的思考--命令模式(读书笔记),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第23章烤羊肉串引来的思考--命令模式

23.1 吃烤羊肉串

23.2 烧烤摊VS烧烤店
 要羊肉做生意的马路游击队,因为要吃烤肉的人太多,大家都希望能最快吃到肉串,而烤肉老板只有一个人,所以有些混乱。买羊肉串的人都盯着烤肉上去了。他们只关心哪一串多,哪一串少,哪一串考得好,这个其实就是行为请求着与行为实现者之间的紧耦合。
 对请求排队或记录请求日志,以及支持可撤销的操作等行为时,行为请求者与行为实现者的紧耦合是不太合适的。而在门店我们只需要给接待我们的服务员说我们要什么就可以了。收钱的时候也不会多收和少收。
 
23.3 紧耦合设计
 路边烤肉的对应。
 

23.4 松耦合设计

 
 抽象命令类, 具体命令类

#pragma once
#include "Barbecuer.h"
class Command
{
public:
Command(BarBecuer* receive)
{
m_pBarbecuer = receive;
};
virtual void ExcuteCommand(void) = 0;
protected:
BarBecuer* m_pBarbecuer;//野餐烤肉的人
};
//烤羊肉串
class BakeMuttonCommand : public Command
{
public:
BakeMuttonCommand(BarBecuer* receive)
:Command(receive)
{
};
void ExcuteCommand(void)
{
m_pBarbecuer->BakeMutton();
};
};
//烤鸡翅
class BakeChickenCommand : public Command
{
public:
BakeChickenCommand(BarBecuer* receive)
:Command(receive)
{
};
void ExcuteCommand(void)
{
m_pBarbecuer->BakeChickenWing();
};
};

服务员类

#pragma once
#include "command.h"
class Waiter
{
public:
//设置订单
void SetOrder(Command* pCommand)
{
m_pCommand = pCommand;
}; 
//通知执行
void Notify()
{
m_pCommand->ExcuteCommand();
};
private:
Command* m_pCommand;
};

羊肉串师傅

#pragma once
#include <iostream>
class BarBecuer
{
public:
void BakeMutton()
{
std::cout << "烤羊肉串" << std::endl;
};
void BakeChickenWing()
{
std::cout << "烤鸡翅" << std::endl;
};
};

 客户端

#include "Waiter.h"
int _tmain(int argc, _TCHAR* argv[])
{
BarBecuer* boy = new BarBecuer();
Command* bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command* bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command* bakeChickenWingCommand1 = new BakeChickenCommand(boy);
Waiter* girl = new Waiter();
girl->SetOrder(bakeMuttonCommand1);
girl->Notify();
girl->SetOrder(bakeMuttonCommand2);
girl->Notify();
girl->SetOrder(bakeChickenWingCommand1);
girl->Notify();
delete bakeMuttonCommand1;
delete bakeMuttonCommand2;
delete bakeChickenWingCommand1;
delete boy;
delete girl;
return 0;
}

 上面这个实现有下面这些问题点:1.用户并不是只点一个菜,2.如果没有鸡翅了,不应该由用户来判断,3.点的菜需要有日志,4.如果菜点了太多,没有取消的操作。

23.5 松耦合后
 这是小菜写的第三版的代码。

#pragma once
#include "command.h"
#include <iostream>
#include <list>
class Waiter
{
public:
//设置订单
void SetOrder(Command* pCommand)
{
m_list.push_back(pCommand);
}; 
//通知执行
void Notify()
{
//m_pCommand->ExcuteCommand();
if( !m_list.empty() )
{
m_iter = m_list.begin();
while(m_iter != m_list.end())
{
(*m_iter)->ExcuteCommand();
++m_iter;
}
}
};
//取消订单
void CancelOrder(Command* pCommand)
{
if( !m_list.empty() )
{
m_list.remove(pCommand);
}
};
private:
std::list<Command*> m_list;
std::list<Command*>::iterator m_iter;
//Command* m_pCommand;
};


 

#include "Waiter.h"
int _tmain(int argc, _TCHAR* argv[])
{
//开店前的准备
BarBecuer* boy = new BarBecuer();
Command* bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command* bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command* BakeChickenCommand1 = new BakeChickenCommand(boy);
Waiter* girl = new Waiter();
//开门营业顾客点菜
girl->SetOrder(bakeMuttonCommand1);
girl->SetOrder(bakeMuttonCommand2);
girl->SetOrder(BakeChickenCommand1);
girl->Notify();
delete boy;
delete bakeMuttonCommand1;
delete bakeMuttonCommand2;
delete BakeChickenCommand1;
delete girl;
return 0;
}

23.6 命令模式
  将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持撤销的操作。
 
 Command类,用来声明执行操作的接口。
 ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接受者相应的操作,以实现Execute。

#pragma once
#include "Receiver.h"
class Command
{
public:
Command(Receiver* receiver)
{
m_receiver = receiver;
};
virtual void Execute(void) = 0;
protected:
Receiver* m_receiver;
};
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver* receiver)
:Command(receiver)
{
};
void Execute(void)
{
m_receiver->Action();
};
};

 Invoker类,要求该命令执行这个请求。

#pragma once
#include "Command.h"
class Invoker
{
public:
void SetCommand(Command* pCommand)
{
m_pCommand = pCommand;
};
void ExecuteCommand()
{
m_pCommand->Execute();
};
private:
Command* m_pCommand;
};

 Receiver类,直到如何实施与执行一个与请求相关的操作,任何类都可能作为一个接受者。

#pragma once
#include <iostream>
class Receiver
{
public:
void Action()
{
std::cout << "执行请求" << std::endl;
};
};

客户端

#include "stdafx.h"
#include "Invoker.h"
int _tmain(int argc, _TCHAR* argv[])
{
Receiver* rec = new Receiver();
Invoker* invoker = new Invoker();
Command* command = new ConcreteCommand(rec);
invoker->SetCommand(command);
invoker->ExecuteCommand();
delete rec;
delete invoker;
delete command;
return 0;
}

23.7 命令模式作用
 第一,它能较容易地设计一个命令队列;第二,在需要的情况下,可以较容易地将命令计入日志;第三,允许接收请求的一方决定是否要否决请求;第四,可以容易地实现对请求的撤销和重做;第五,由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。其实还有最关键的优点就是命令模式把请求一个操作的对象与直到怎么执行一个操作的对象分割开。
 敏捷开发原则告诉我们,不要为代码添加基于猜测的,实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
 再回到羊肉串的话题来,当服务员搞错价格的时候,服务员做了记录,也就是记日志,所以可以很快纠正过来。而单就烤肉串的人,哪里记得住烤了多少串,如果人一多,则必定会搞错。

这篇关于第二十三章烤羊肉串引来的思考--命令模式(读书笔记)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/832338

相关文章

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java -jar命令如何运行外部依赖JAR包

《Java-jar命令如何运行外部依赖JAR包》在Java应用部署中,java-jar命令是启动可执行JAR包的标准方式,但当应用需要依赖外部JAR文件时,直接使用java-jar会面临类加载困... 目录引言:外部依赖JAR的必要性一、问题本质:类加载机制的限制1. Java -jar的默认行为2. 类加

git stash命令基本用法详解

《gitstash命令基本用法详解》gitstash是Git中一个非常有用的命令,它可以临时保存当前工作区的修改,让你可以切换到其他分支或者处理其他任务,而不需要提交这些还未完成的修改,这篇文章主要... 目录一、基本用法1. 保存当前修改(包括暂存区和工作区的内容)2. 查看保存了哪些 stash3. 恢

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

MySQL的ALTER TABLE命令的使用解读

《MySQL的ALTERTABLE命令的使用解读》:本文主要介绍MySQL的ALTERTABLE命令的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、查看所建表的编China编程码格式2、修改表的编码格式3、修改列队数据类型4、添加列5、修改列的位置5.1、把列

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S