元素
- 抽象命令/具體命令
- 抽象接受者/具體接受者
- 調(diào)用者
- 客戶端
應(yīng)用場(chǎng)景舉例
這里我們用一個(gè)場(chǎng)景來描述:去川湘閣飯店點(diǎn)一份剁椒魚頭和宮保雞丁拐格。
這里我們把整個(gè)關(guān)鍵流程寫出來
- 點(diǎn)菜下單
- 收銀臺(tái)出單
- 廚房收到抄菜單绢片,分給具體廚師
- 廚師炒菜
接下來我們就可以抽象出具體的角色改橘∶峭客戶端當(dāng)然就是我們的用戶自脯,調(diào)用者就是收銀臺(tái)出單的妹紙贞谓,命令就是抄菜單十性,接受者就是廚師叛溢。這樣就很清晰了,客戶端(用戶)不需要知道功能(炒菜)怎么實(shí)現(xiàn)或者誰(shuí)實(shí)現(xiàn)劲适,他只需要找調(diào)用者(服務(wù)員/前臺(tái))描述清楚楷掉,然后調(diào)用者發(fā)命令給接受者(廚師),然后接受者執(zhí)行命令(炒菜)霞势。 這個(gè)流程非常的清晰也不會(huì)出錯(cuò)烹植。什么樣的命令給什么樣的接受者執(zhí)行,比如:剁椒魚頭愕贡,就打剁椒魚頭的票草雕,然后指定給會(huì)做剁椒魚頭的師傅做。宮保雞丁就給會(huì)做宮保雞丁的師傅做固以。這個(gè)過程中墩虹,命令(小票)包含接受者(師傅)的信息。不同的命令對(duì)應(yīng)不同的接受者憨琳。所以這里建立命令和接受者的抽象诫钓。
優(yōu)點(diǎn)
- 將請(qǐng)求的發(fā)起者和執(zhí)行者接口,通過命令來實(shí)現(xiàn)篙螟,將客戶端的調(diào)用參數(shù)化菌湃。只需要將每個(gè)動(dòng)作封裝正命令,由發(fā)起者命令執(zhí)行者來執(zhí)行
- 請(qǐng)求排隊(duì)遍略、記錄每個(gè)請(qǐng)求惧所。拿上面的場(chǎng)景來說场梆,當(dāng)很多客人點(diǎn)了剁椒魚頭時(shí),廚師可能做不過來纯路,這時(shí)候就得排隊(duì)或油,先來的先做。
示例(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 << "請(qǐng)先設(shè)置廚師" << endl;
}
int res = chef->cooking(id);
}
ChuangXiangGeOrder::~ChuangXiangGeOrder()
{
}
抽象調(diào)用者(下單服務(wù)員)
#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() {}
};
具體調(diào)用者(川湘閣的下單服務(wù)員)
#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 << "請(qǐng)先下單" << endl;
}
order->make();
}
ChuanXiangGeWaiter::~ChuanXiangGeWaiter()
{
}
測(cè)試代碼
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;
}
結(jié)果:
java版
線程池
Executor就是抽象調(diào)用者
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);
}
我們看到其中一個(gè)實(shí)現(xiàn)類ThreadPoolExecutor
看到Executor的源碼驰唬,我們看到參數(shù)的起名都是command顶岸。這里Runable就是抽象的命令。那接受者呢叫编。其實(shí)這里的接受者也是Runable辖佣。同時(shí)ThreadPoolExecutor除了能夠發(fā)起命令外,還可以對(duì)Runable進(jìn)行排隊(duì)搓逾。這里我們用一個(gè)例子說明
測(cè)試
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);
}
}
結(jié)果
1 TaskA begin
2 TaskA begin
3 TaskA begin
1 TaskA end
3 TaskA end
2 TaskA end
4 TaskA begin
4 TaskA end