組合模式
簡介
將對象組合成樹形結構以表示“部分-整體”的層次結構。
組合模式使得用戶對單個對象和組合對象的使用具有一致性。
動機
總部、分部和辦事處是成樹狀結構,也就是有組織結構的,不可以簡單的平行管理。
希望總公司的組織結構,比如人力資源部、財務部的管理功能可以複用於分公司。這其實是整體與部分可以被一致對待的問題。
適用性
想表示對象的“部分-整體”層次結構。
希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
結構
參與者
Component
爲組合中的對象聲明接口。
在適當的情況下,實現所有類共有接口的缺省行爲。
聲明一個接口用於訪問和管理Component的子組件。
在遞歸結構中定義一個接口,用於訪問一個父部件,並在合適的情況下實現它。(可選)
Leaf
在組合中表示葉節點對象,葉節點沒有子節點。
在組合中定義葉節點對象的行爲。
Composite
定義有子部件的那些部件的行爲。
存儲子部件。
在Component接口中實現與子部件有關的操作。
Client
通過Component接口操縱組合部件的對象。
協作
用戶使用Component類接口與組合結構中的對象進行交互。
如果接收者是一個葉節點,則直接處理請求。
如果接收者是一個Composite,它通常將請求發送給它的子部件,在轉發請求之前與/或之後可能執行一些輔助操作。
效果
定義了包含基本對象和組合對象的類層次結構。
簡化客戶代碼。
使得更容易添加新類型的組件。
職責鏈模式
簡介
爲解除請求的發送者和接收者之間的耦合,而使多個對象都有機會處理這個請求。
將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,指導有一個對象處理它爲止。
動機
考慮公司中的請假申請。
公司中管理人員按等級從低到高分別有:經理、總監、總經理。
請假需要根據天數長短,向不同等級的管理人員申請,例如少於2天直接向經理申請即可,少於一週必須要總監批准,更長時間則需要總經理批准。
適用性
有多個對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。
想在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
可處理一個請求的對象集合應被動態指定。
結構
參與者
Handler
定義一個處理請求的接口。
實現後繼鏈。
ConcreteHandler
處理它所負責的請求。
可訪問它的後繼者。
如果可處理該請求,就處理之;否則將該請求轉發給它的後繼者。
Client
向鏈上的ConcreteHandler對象提交請求。
效果
降低耦合度。
增強了給對象指派職責的靈活性。
不保證被接受。
實例
根據下圖,利用組合模式構建該公司的結構。
即總公司下設上海華東分公司,華東分公司下設南京辦事處和杭州辦事處。其中,各級分公司均設有人力資源部和財務部。
利用組合模式構建好該結構後,利用職責鏈模式處理各地員工加薪請求。
例如,一南京員工提出加薪請求,如果加薪不超過1000元,南京辦事處即可批准;如果超過1000元,則上報華東分公司,如果2000元以內,則批准;超過則上報北京總公司,如果不超過3000元,則總公司批准,否則拒絕。
UML
組合模式Component是對象聲明接口,對應於職責鏈模式的Handler,兩個模式的代碼可以合併。
另外通過增加low, bound兩個變量來控制if語句數量,減少類的數目。因此職責鏈中的多個ConcreteHandler對應於一個具體的ConcreteCompany。
代碼
#include<iostream>
#include<list>
#include <typeinfo>
using namespace std;
class Component{
public:
Component(string name){
this->name = name;
}
virtual void Add(Component* c) = 0;
virtual void Remove(Component* c) = 0;
virtual void Display(int depth) = 0;
void SetSuccessor(Component* s){
this->successor = s;
}
void SetBound(int low, int high){
this->low = low;
this->high = high;
}
virtual void HandleReauest(int request) = 0;
protected:
string name;
int low, high;
Component* successor;
};
class Subcom : public Component{
public:
Subcom(string name) : Component(name){}
void Add(Component* c){
cout<<"Cannot add to a leaf";
}
void Remove(Component* c){
cout<<"Cannot remove from a leaf";
}
void Display(int depth){
for(int i = 0; i <= depth; i++)
cout<<"--";
cout<<name<<endl;
}
void HandleReauest(int request){
}
};
class ConcreteCompany: public Component{
private:
list<Component*> children;
public:
ConcreteCompany(string name): Component(name){}
void Add(Component *c){
children.push_back(c);
}
void Remove(Component *c){
children.remove(c);
}
void Display(int depth){
for(int i = 0; i <= depth; i++)
cout<<"--";
cout<<name<<endl;
for(Component* child : children){
child->Display(depth + 1);
}
}
void HandleReauest(int request){
if(request >= low && request <= high){
cout<<this->name<<"處理請求: "<<request<<endl;
}else if(successor != NULL){
cout<<this->name<<"處理失敗"<<endl;
successor->HandleReauest(request);
}else{
cout<<this->name<<"加薪拒絕"<<request<<endl;
}
}
};
/*
即總公司下設上海華東分公司,華東分公司下設南京辦事處和杭州辦事處。其中,各級分公司均設有人力資源部和財務部。
用組合模式構建好該結構後,利用職責鏈模式處理各地員工加薪請求。
例如,一南京員工提出加薪請求,如果加薪不超過1000元,南京辦事處即可批准;如果超過1000元,則上報華東分公司,如果2000元以內,則批准;超過則上報北京總公司,如果不超過3000元,則總公司批准,否則拒絕。、
實驗報告內容:
*/
int main(){
Component *root = new ConcreteCompany("總公司");
root->Add(new Subcom("人力資源部"));
root->Add(new Subcom("財務部"));
root->SetBound(2000, 3000);
Component *huadong = new ConcreteCompany("上海華東分公司");
huadong->Add(new Subcom("人力資源部"));
huadong->Add(new Subcom("財務部"));
huadong->SetBound(1000, 2000);
Component *nanjing = new ConcreteCompany("南京辦事處");
nanjing->Add(new Subcom("人力資源部"));
nanjing->Add(new Subcom("財務部"));
nanjing->SetBound(0, 1000);
Component *hanzhou = new ConcreteCompany("杭州辦事處");
hanzhou->Add(new Subcom("人力資源部"));
hanzhou->Add(new Subcom("財務部"));
hanzhou->SetBound(0, 1000);
nanjing->SetSuccessor(huadong);
hanzhou->SetSuccessor(huadong);
huadong->SetSuccessor(root);
root->SetSuccessor(NULL);
huadong->Add(nanjing);
huadong->Add(hanzhou);
root->Add(huadong);
root->Display(1);
cout<<"*********************"<<endl;
nanjing->HandleReauest(100);
cout<<"*********************"<<endl;
hanzhou->HandleReauest(1500);
cout<<"*********************"<<endl;
hanzhou->HandleReauest(2100);
cout<<"*********************"<<endl;
hanzhou->HandleReauest(3100);
return 0;
}
//
結果
總結
①本次需要將職責鏈模式與組合模式合併,其中組合模式Component是對象聲明接口,對應於職責鏈模式的Handler。
②組合模式中的節點需要放到當前父節點的list中,對於容器list,需要掌握對應的STL語句。
③對於職責鏈模式,爲了減少類的數量和耦合需要設置low和high兩個上下界。類雖然少了,但是對象沒有減少,這些對象形成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理了它爲止。通過當前對象的name來指示客戶端選擇。
更多內容訪問 omegaxyz.com
網站所有代碼採用Apache 2.0授權
網站文章採用知識共享許可協議BY-NC-SA4.0授權
© 2019 • OmegaXYZ-版權所有 轉載請註明出處