基于集合派生对象中存在的类型选择行为的模式
Pattern for choosing behaviour based on the types present in a collection derived objects
我有一组代表系统模型的对象。这些对象中的每一个都派生自代表抽象 "component" 的基础 class。我希望能够查看系统并根据存在的组件和顺序选择某些行为。
为了便于论证,我们称基数为 class Component
,实际的分量为 InputFilter
、OutputFilter
和 Processor
。我们可以处理的系统是带有 Processor
和一个或两个过滤器的系统。实际系统有更多的类型,它们之间的交互也更复杂,但我认为现在就可以了。
我可以看到两种 "simple" 方法可以使用 marshalComponentSettings()
函数来处理这种情况,该函数采用其中一个集合并计算出如何最有效地设置每个节点。这可能需要以某些方式修改输入或以不同方式拆分它们,因此它并不像每个组件实现一个虚拟 handleSettings()
函数那么简单。
首先是使用纯虚函数从每个 class 报告一个枚举类型,并使用它们来计算要做什么,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 的理想候选者,具有以下角色(参见 link 中的 UML 架构):
- objectStructure:您的模型,也就是
Component
的集合
- 元素:你的
Component
基础class
- concreteElementX:您的实际组件(
InputFilter
、OutputFilter
、Processor
、...)
- 访问者:必须将模型作为一组一致的元素来管理的抽象算法系列。
- concreteVisitorA:你的配置过程。
主要优点:
您的 configuration/set-up 符合设计模式的意图:要对对象结构的元素执行的操作。相反,此模式允许您考虑遍历期间遇到的元素的顺序和种类,因为访问者可以是 stateful。
一个积极的副作用是访问者模式将使您的设计具有灵活性,可以轻松添加具有相似遍历但目的不同的新 processes/algortihms(例如:系统定价,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;
...
};
挑战:
访问者面临的主要挑战是安装程序可以更改配置本身(替换组件?更改顺序),因此您必须注意保持容器上的连续迭代器,同时确保不要多次处理项目。
最佳方法取决于容器的类型,以及您的设置所做的更改类型。但是您肯定需要一些标志来查看哪个元素已被处理,或者一个临时容器(已处理的元素或剩余待处理的元素)。
无论如何,由于访问者是class,它还可以将任何此类状态数据封装在私有成员中。
我有一组代表系统模型的对象。这些对象中的每一个都派生自代表抽象 "component" 的基础 class。我希望能够查看系统并根据存在的组件和顺序选择某些行为。
为了便于论证,我们称基数为 class Component
,实际的分量为 InputFilter
、OutputFilter
和 Processor
。我们可以处理的系统是带有 Processor
和一个或两个过滤器的系统。实际系统有更多的类型,它们之间的交互也更复杂,但我认为现在就可以了。
我可以看到两种 "simple" 方法可以使用 marshalComponentSettings()
函数来处理这种情况,该函数采用其中一个集合并计算出如何最有效地设置每个节点。这可能需要以某些方式修改输入或以不同方式拆分它们,因此它并不像每个组件实现一个虚拟 handleSettings()
函数那么简单。
首先是使用纯虚函数从每个 class 报告一个枚举类型,并使用它们来计算要做什么,
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 的理想候选者,具有以下角色(参见 link 中的 UML 架构):
- objectStructure:您的模型,也就是
Component
的集合
- 元素:你的
Component
基础class - concreteElementX:您的实际组件(
InputFilter
、OutputFilter
、Processor
、...) - 访问者:必须将模型作为一组一致的元素来管理的抽象算法系列。
- concreteVisitorA:你的配置过程。
主要优点:
您的 configuration/set-up 符合设计模式的意图:要对对象结构的元素执行的操作。相反,此模式允许您考虑遍历期间遇到的元素的顺序和种类,因为访问者可以是 stateful。
一个积极的副作用是访问者模式将使您的设计具有灵活性,可以轻松添加具有相似遍历但目的不同的新 processes/algortihms(例如:系统定价,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;
...
};
挑战:
访问者面临的主要挑战是安装程序可以更改配置本身(替换组件?更改顺序),因此您必须注意保持容器上的连续迭代器,同时确保不要多次处理项目。
最佳方法取决于容器的类型,以及您的设置所做的更改类型。但是您肯定需要一些标志来查看哪个元素已被处理,或者一个临时容器(已处理的元素或剩余待处理的元素)。
无论如何,由于访问者是class,它还可以将任何此类状态数据封装在私有成员中。