元素
- 抽象命令/具体命令
- 抽象接受者/具体接受者
- 调用者
- 客户端
应用场景举例
这里我们用一个场景来描述:去川湘阁饭店点一份剁椒鱼头和宫保鸡丁。
这里我们把整个关键流程写出来
- 点菜下单
- 收银台出单
- 厨房收到抄菜单,分给具体厨师
- 厨师炒菜
接下来我们就可以抽象出具体的角色。客户端当然就是我们的用户,调用者就是收银台出单的妹纸,命令就是抄菜单,接受者就是厨师。这样就很清晰了,客户端(用户)不需要知道功能(炒菜)怎么实现或者谁实现,他只需要找调用者(服务员/前台)描述清楚,然后调用者发命令给接受者(厨师),然后接受者执行命令(炒菜)。 这个流程非常的清晰也不会出错。什么样的命令给什么样的接受者执行,比如:剁椒鱼头,就打剁椒鱼头的票,然后指定给会做剁椒鱼头的师傅做。宫保鸡丁就给会做宫保鸡丁的师傅做。这个过程中,命令(小票)包含接受者(师傅)的信息。不同的命令对应不同的接受者。所以这里建立命令和接受者的抽象。
优点
- 将请求的发起者和执行者接口,通过命令来实现,将客户端的调用参数化。只需要将每个动作封装正命令,由发起者命令执行者来执行
- 请求排队、记录每个请求。拿上面的场景来说,当很多客人点了剁椒鱼头时,厨师可能做不过来,这时候就得排队,先来的先做。
示例(C++版):
接受者(厨师)抽象类
#include<iostream>
using namespace std;
class Chef
{
public:
virtual int cooking(int id)=0;
virtual void printTicketIds()const = 0;
virtual ~Chef() {}
};
具体接受者(川湘阁做剁椒鱼头的厨师)类
#include "Chef.h"
class FishChef :
public Chef
{
int id;
string name;
deque<int> ticketIds;
public:
FishChef(int id, string name);
int cooking(int id);
void printTicketIds()const;
~FishChef();
};
#include "FishChef.h"
FishChef::FishChef(int id, string name)
{
this->id = id;
this->name = name;
}
FishChef::~FishChef()
{
}
void FishChef::printTicketIds()const {
cout << "id为" << this->id << " 姓名为:" << this->name.c_str() << "的厨师需要做的菜";
for (deque<int>::const_iterator it = ticketIds.begin(); it != ticketIds.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int FishChef::cooking(int id) {
if (ticketIds.size() > 3) {
return 1;
}
ticketIds.push_back(id);
return 0;
}
抽象命令(炒菜单)
#include<iostream>
#include "Chef.h"
using namespace std;
class Order
{
protected :
Chef* chef;
public:
Order(Chef* chef) {
this->chef = chef;
}
virtual void make()=0;
~Order() {
if (chef != NULL)
delete chef;
}
};
具体命令(川湘阁的抄菜单)
#include "stdafx.h"
#include "ChuangXiangGeOrder.h"
ChuangXiangGeOrder::ChuangXiangGeOrder(Chef * chef, int id):Order(chef)
{
this->id = id;
}
void ChuangXiangGeOrder::make()
{
if (chef == NULL) {
cout << "请先设置厨师" << endl;
}
int res = chef->cooking(id);
}
ChuangXiangGeOrder::~ChuangXiangGeOrder()
{
}
抽象调用者(下单服务员)
#include<iostream>
#include<vector>
#include<string>
#include"Order.h"
using namespace std;
using namespace std;
class Waiter
{
protected:
Order* order;
public:
Waiter() {}
virtual pair<int,string> setOrder(Order* order)=0;
virtual void execute()=0;
~Waiter() {}
};
具体调用者(川湘阁的下单服务员)
#include "stdafx.h"
#include "ChuanXiangGeWaiter.h"
ChuanXiangGeWaiter::ChuanXiangGeWaiter()
{
}
pair<int, string> ChuanXiangGeWaiter::setOrder(Order* order)
{
Waiter::order = order;
return pair<int, string>();
}
void ChuanXiangGeWaiter::execute()
{
if (order == NULL) {
cout << "请先下单" << endl;
}
order->make();
}
ChuanXiangGeWaiter::~ChuanXiangGeWaiter()
{
}
测试代码
int main()
{
Chef *chef = new FishChef(1, "张厨师");
Order *order = new ChuangXiangGeOrder(chef,1001);
Waiter *waiter = new ChuanXiangGeWaiter();
waiter->setOrder(order);
waiter->execute();
chef->printTicketIds();
Order *order1 = new ChuangXiangGeOrder(chef, 1002);
waiter->setOrder(order1);
waiter->execute();
chef->printTicketIds();
Order *order2 = new ChuangXiangGeOrder(chef, 1003);
waiter->setOrder(order2);
waiter->execute();
chef->printTicketIds();
return 0;
}
结果:
java版
线程池
Executor就是抽象调用者
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
我们看到其中一个实现类ThreadPoolExecutor
看到Executor的源码,我们看到参数的起名都是command。这里Runable就是抽象的命令。那接受者呢。其实这里的接受者也是Runable。同时ThreadPoolExecutor除了能够发起命令外,还可以对Runable进行排队。这里我们用一个例子说明
测试
public class TestMain {
public static void main(String[] args) {
new Thread(new TaskA(1)).start();
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new TaskA(2));
executor.execute(new TaskA(3));
executor.execute(new TaskA(4));
}
static class TaskA implements Runnable {
private int id;
public TaskA(int id) {
this.id = id;
}
public void run() {
log(id+" TaskA begin");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log(id+" TaskA end");
}
}
public static void log(String content) {
System.out.println(content);
}
}
结果
1 TaskA begin
2 TaskA begin
3 TaskA begin
1 TaskA end
3 TaskA end
2 TaskA end
4 TaskA begin
4 TaskA end