我有一组代表系统模型的对象。这些对象中的每一个都派生自代表抽象“组件”的基类。我希望能够查看系统并根据存在的组件及其顺序选择某些行为。
为了论证,我们将基类称为Component
,将实际组件称为InputFilter
、OutputFilter
和Processor
。我们可以处理的系统是带有 Processor
和一个或两个过滤器的系统。实际系统的类型更多,它们之间的交互也更复杂,但我认为现在就可以了。
我可以通过 marshalComponentSettings()
函数看到两种“简单”的方法来处理这种情况,该函数采用其中一个集合并计算出如何最有效地设置每个节点。这可能需要以特定方式修改输入或以不同方式拆分它们,因此它并不像为每个组件实现一个虚拟 handleSettings()
函数那么简单。
第一个是使用纯虚函数报告每个类的枚举类型,并使用它们来确定要做什么,
dynamic_cast
'ing 在需要访问组件特定选项的地方。enum CompType { INPUT_FILTER, OUTPUT_FILTER, PROCESSOR } void marshal(Settings& stg) { if (comps[0].type() == INPUT_FILTER) setUpInputFilter(stg); //maybe modified the stg, or provides other feedback of what was done // something similar for outputs setUpProcessor(stg); }
第二个是
dynamic_cast
到这个函数中可能是一个选项的任何东西,并使用它的成功与否(以及可能的转换对象,如果需要的话)来确定什么做。void marshal(Settings& stg) { if (InputFilter* filter = dynamic_cast<InputFilter*>(comp[0])) setUpInputFilter(stg); //maybe modified the stg, or provides other feedback of what was done // something similar for outputs setUpProcessor(stg); }
似乎第一种是最有效的方法(不需要推测性地测试每个对象以找出它是什么),但即使那样似乎也不太正确(可能是由于那些烦人的细节设备相互影响并泄漏到通用编码代码中)。
有没有比嵌套的条件判断行为更优雅的方式来处理这种情况?甚至是情况或模式的名称?
最佳答案
您的场景似乎是 visitor design pattern 的理想候选者,具有以下角色(请参阅链接中的 UML 模式):
- objectStructure:您的模型,也就是
Component
的集合 - 元素:您的
组件
基类 - concreteElementX:您的实际组件(
InputFilter
、OutputFilter
、Processor
、...) - 访问者:必须将您的模型作为一组一致的元素来管理的抽象算法系列。
- concreteVisitorA:你的配置过程。
主要优势:
您的配置/设置符合设计模式的意图:要对对象结构的元素执行的操作。相反,此模式允许您考虑遍历期间遇到的元素的顺序和种类,因为访问者可以有状态。
一个积极的副作用是访问者模式将使您的设计具有灵 active ,可以轻松添加具有相似遍历但目的不同的新流程/算法(例如:系统定价、 Material 计划等...)
class Visitor;
class Component {
public:
virtual void accept(class Visitor &v) = 0;
};
class InputFilter: public Component {
public:
void accept(Visitor &v) override; // calls the right visitor function
};
...
class Visitor
{
public:
virtual void visit(InputFilters *c) = 0; // one virtual funct for each derived component.
virtual void visit(Processor *c) = 0;
...
};
void InputFilter::accept(Visitor &v)
{ v.visit(this); }
...
class SetUp : public Visitor {
private:
bool hasProcessor;
int impedenceFilter;
int circuitResistance;
public:
void visit(InputFilters *c) override;
void visit(Processor *c) override;
...
};
挑战:
访问者面临的主要挑战是设置可以更改配置本身(替换组件?更改顺序),因此您必须注意保持一致容器上的迭代器,同时确保不要多次处理项目。
最佳方法取决于容器的类型,以及您的设置所做的更改类型。但是您肯定需要一些标志来查看哪个元素已被处理,或者一个临时容器(已处理的元素或剩余待处理的元素)。
无论如何,由于访问者是一个类,它还可以将任何此类状态数据封装在私有(private)成员中。
关于c++ - 基于集合派生对象中存在的类型选择行为的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30260441/