[英]C++: Applying the Composite pattern
我正在嘗試應用Composite模式,因此我需要創建一個Leaf類和一個Composite類,它們都繼承自同一個Component類。 為了讓我的任何組件履行其職責,他們需要從單個Helper對象請求幫助。 我們有以下內容
struct Helper {
void provide_help();
};
struct Component {
Component(Helper* helper)
: m_helper(helper) {
}
virtual void operation() = 0;
// the call_for_help function will be used by subclasses of Component to implement Component::operation()
void call_for_help() {
m_helper->provide_help();
}
private:
Helper* m_helper;
};
這里有兩個不同的Leaf子類:
struct Leaf1
: Component {
Leaf1(Helper* helper)
: Component(helper) {
}
void operation() override {
call_for_help();
operation1();
}
void operation1();
};
struct Leaf2
: Component {
Leaf2(Helper* helper)
: Component(helper) {
}
void operation() override {
call_for_help();
operation2();
}
void operation2();
};
到現在為止還挺好。 現在復合課讓我感到悲傷。 典型的實現如下
struct Composite
: Component {
Composite(Helper* helper)
: Component(helper) {
}
void operation() override {
for (auto el : m_children) el->operation();
}
private:
std::vector<Component*> m_children;
};
通過m_children
並在每個上調用operation
本質上多次調用輔助函數,即使一個調用對所有子m_children
都足夠。 理想情況下,如果m_children
由Leaf1
和Leaf2
,我想以某種方式復合操作只調用一次輔助函數,然后連續調用Leaf1 :: operation1()然后調用Leaf2 :: operation2()。 有沒有辦法達到我的需要? 歡迎替代設計。 我希望我的問題有道理。 提前致謝!
您需要多態操作,但是您要為方法添加更多響應(調用幫助程序)。 分開這兩件事情會更好。
struct Component {
void call_operation(){
call_for_help();
operation();
}
virtual void operation() = 0;
void call_for_help();
};
從leaf :: operation()中移除call_for_help()(使operation1,operation2冗余,多態),其余的應該可以正常工作。
您甚至可以從公共界面隱藏operation(),在這種情況下,您需要與Composite建立友誼。
因為它可能發生在任何級別,一種方法可能是在幫助程序級別處理此問題。
該方法的草圖將是:
class Helper {
bool composite_help = false;
bool help_provided;
public:
void provide_help() {
if ((composite_help && !help_provided) || !composite_help) {
//TO DO: provide help
help_provided = true;
}
}
void start_composite_help() {
composite_help = true;
help_provided = false;
}
void end_composite_help() {
composite_help = false;
}
};
原則是由各個組件執行的求助程序的工作方式與以前一樣。 但是當復合調用求助時,您需要進行預抽真空以確保調用僅執行一次:
void operation() override {
m_helper->start_composite_help();
for (auto el : m_children) el->operation();
m_helper->start_composite_help();
}
如上所述,這只是一個草圖:如果您有多個級別的復合材料,那么這樣提供的代碼將無法正常工作。 所以這需要改進:
而不是bool composite_help
你需要一個計數器,它在輸入復合操作時遞增,在退出時遞減。 在這種情況下,只有當最后一級composte完成其工作時,計數器才會返回0(重新啟用幫助)。
可能是幫助者執行不同的操作來提供幫助。 因此,您還可以設想具有唯一標識一組相關操作的“事務ID”,並且在活動事務的映射中管理計數器而不是整體幫助程序。
最后,開始/結束並不是那么好。 幫助程序的RAII幫助程序可以使整個設置更加健壯(例如,當異常中斷正常執行流程時)。
我認為使用Composite和Mediator的組合可以更好地解決這個問題。
小心! 我將向您展示不同版本的中介模式,這與規范版本不同。
知道是否調用了幫助程序並不是復合結構的業務。 你最好使用某種事件處理程序來做這件事。
由於你只有一個助手,你可以嘗試這樣:
class Helper {
public:
void callHelper() { std::cout << "Helper called" << std::endl; }
};
class Mediator {
private:
std::map<std::string, std::vector<Helper>> subscribers;
int updateLimit = -1;
int currentUpdateCount = 0;
void resetUpdateCount() {
currentUpdateCount = 0;
}
public:
Mediator(){}
void subscribe(std::string evt, Helper helper) {
subscribers[evt].push_back(helper);
}
void update(std::string evt) {
for (auto& h: subscribers[evt]) {
h.callHelper();
}
}
void setUpdateLimit(int i) {
updateLimit = i;
resetUpdateCount();
}
void removeUpdateLimit() {
updateLimit = -1;
resetUpdateCount();
}
int getUpdateLimit() {
return updateLimit;
}
void updateLimited(std::string evt) {
if (updateLimit < 0 || currentUpdateCount < updateLimit) {
update(evt);
currentUpdateCount++;
}
}
};
int main(int argc, const char *argv[])
{
Mediator m;
Helper h1, h2;
m.subscribe("bar", h1);
m.setUpdateLimit(1);
// Will be called only once
m.updateLimited("bar");
m.updateLimited("bar");
m.updateLimited("bar");
m.removeUpdateLimit();
return 0;
}
使用它:
Mediator m;
Helper h1, h2;
m.subscribe("bar", h1);
m.setUpdateLimit(1);
// Will be called only once
m.updateLimited("bar");
m.updateLimited("bar");
m.updateLimited("bar");
m.removeUpdateLimit();
因此,您可以采用以下方法將其集成到復合結構中。 從您的節點中刪除幫助程序,將Mediator
添加到基類:
struct Component {
Component(Mediator& mediator)
: m_helper(mediator) {
}
virtual void operation() = 0;
// the call_for_help function will be used by subclasses of Component to implement Component::operation()
void notify() {
m_mediator->updateFiltered(Component::updateEventName);
}
static std::string updateEventName;
private:
Mediator& m_mediator;
};
std::string Component::updateEventName = "update.composite";
struct Leaf1
: Component {
Leaf1(Helper* helper)
: Component(helper) {
}
void operation() override {
notify();
operation1();
}
void operation1();
};
使用它:
Mediator m;
Helper h;
Composite c(m);
Leaf1 l1(m), l2(m);
c.add(l1);
c.add(l2);
m.subscribe(Component::updateEventName, h);
m.setUpdateLimit(1);
// Will be called only once, even if it has childrens
c.update();
m.removeUpdateLimit();
重要說明:此解決方案不是最理想的,它存在一些問題,例如您必須將中介實例傳遞給每個節點構造函數,但這對您來說只是一個原始想法。
希望能幫助到你!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.