組合模式與職責鏈模式編程實現

組合模式

簡介

將對象組合成樹形結構以表示“部分-整體”的層次結構。
組合模式使得用戶對單個對象和組合對象的使用具有一致性。
動機

總部、分部和辦事處是成樹狀結構,也就是有組織結構的,不可以簡單的平行管理。
希望總公司的組織結構,比如人力資源部、財務部的管理功能可以複用於分公司。這其實是整體與部分可以被一致對待的問題。
適用性

想表示對象的“部分-整體”層次結構。
希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
結構

在這裏插入圖片描述
參與者

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-版權所有 轉載請註明出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章