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

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

第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

相关文章

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

Spring Boot项目部署命令java -jar的各种参数及作用详解

《SpringBoot项目部署命令java-jar的各种参数及作用详解》:本文主要介绍SpringBoot项目部署命令java-jar的各种参数及作用的相关资料,包括设置内存大小、垃圾回收... 目录前言一、基础命令结构二、常见的 Java 命令参数1. 设置内存大小2. 配置垃圾回收器3. 配置线程栈大小

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

Linux find 命令完全指南及核心用法

《Linuxfind命令完全指南及核心用法》find是Linux系统最强大的文件搜索工具,支持嵌套遍历、条件筛选、执行动作,下面给大家介绍Linuxfind命令完全指南,感兴趣的朋友一起看看吧... 目录一、基础搜索模式1. 按文件名搜索(精确/模糊匹配)2. 排除指定目录/文件二、根据文件类型筛选三、时间

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

Windows命令之tasklist命令用法详解(Windows查看进程)

《Windows命令之tasklist命令用法详解(Windows查看进程)》tasklist命令显示本地计算机或远程计算机上当前正在运行的进程列表,命令结合筛选器一起使用,可以按照我们的需求进行过滤... 目录命令帮助1、基本使用2、执行原理2.1、tasklist命令无法使用3、筛选器3.1、根据PID

Linux系统之authconfig命令的使用解读

《Linux系统之authconfig命令的使用解读》authconfig是一个用于配置Linux系统身份验证和账户管理设置的命令行工具,主要用于RedHat系列的Linux发行版,它提供了一系列选项... 目录linux authconfig命令的使用基本语法常用选项示例总结Linux authconfi