[英]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.