用于根据集合派生对象中存在的类型选择行为的模式

时间:2015-05-15 13:11:33

标签: c++ oop inheritance design-patterns virtual-functions

我有一组对象,代表系统的模型。这些对象中的每一个都派生自一个表示抽象"组件"的基类。我希望能够查看系统,并根据存在的组件和顺序选择某些行为。

为了论证,我们调用基类Component和实际组件InputFilterOutputFilterProcessor。我们可以处理的系统是具有Processor和一个或两个过滤器的系统。实际的系统有更多类型和更复杂的交互,但我认为现在这样做。

我可以看到两个"简单"使用marshalComponentSettings()函数处理这种情况的方法,该函数采用其中一个集合并找出如何最有效地设置每个节点。这可能需要以某种方式修改输入或以不同的方式将它们拆分,因此它不像每个组件实现虚拟handleSettings()函数那么简单。

  • 第一种是使用纯虚函数从每个类报告枚举类型,并使用这些来计算要执行的操作,dynamic_cast以及访问组件特定选项所需的位置。

    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);
    }
    

似乎第一种是最有效的方法(不需要推测性地测试每个物体以找出它是什么),但即使这样看起来也不对(可能是因为这很烦人)这些设备如何相互影响泄漏到一般封送代码中的细节。)

有没有一种更优雅的方法来处理这种情况,而不是一组条件确定行为?甚至是情况或模式的名称?

1 个答案:

答案 0 :(得分:1)

您的方案似乎是 visitor design pattern 的理想候选者,具有以下角色(请参阅链接中的UML架构):

  • objectStructure:您的模型,又名Component
  • 的集合
  • 元素:您的Component基类
  • concreteElementX:您的实际组件(InputFilterOutputFilterProcessor,...)
  • visitor:必须将模型作为一组一致元素进行管理的抽象算法族。
  • concreteVisitorA:您的配置过程。

主要优势:

您的配置/设置对应于设计模式的意图:要对对象结构的元素执行的操作。相反,此模式允许您考虑遍历期间遇到的元素的顺序和类型,因为访问者可以 有状态

一个积极的副作用是,访问者模式将为您的设计提供灵活性,可以轻松添加具有类似遍历但目的不同的新流程/算法(例如:系统定价,物料计划等等)

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; 
    ... 
};

<强>挑战:

您对访问者的主要挑战,但也有其他选择,是设置可以更改配置本身(替换组件?更改顺序),因此您必须照顾保持一个合作伙伴容器上的迭代器,同时确保不要多次处理项目。

最佳方法取决于容器的类型以及设置正在执行的更改类型。但是你肯定需要一些标志来查看哪个元素已被处理,或者是一个临时容器(处理的元素或剩余要处理的元素)。

在任何情况下,由于访问者是一个类,它还可以将任何此类状态数据封装在私有成员中。