战略模式与继承

时间:2018-01-23 09:11:26

标签: c++ oop inheritance design-patterns strategy-pattern

我们有一些算法适用于某些数据,算法可能会在同一数据上多次应用。我们有两种方法可以做到这一点:

  1. 保持数据和逻辑分离

    class Algo{
    public:
        virtual int execute(data_object) = 0;
    };
    
    class AlgoX: public Algo{
    public:
        int execute(data_object);
    };
    
    class AlgoY: public Algo{
    public:
        int execute(data_object);
    };
    
    class Data{
    public:
        string some_values;
        ...
        void* algo_specific_data; //It will contain some algo specific data (like state of algo)
        Algo* algo_ptr; //Reference of Algo
    
        int execute(){
            algo_ptr->execute(this);
        }
    };
    
    some_function(){
        Data* data_object = create_data(algo_ptr, algo_specific_data); //A dummy function which creates an object of type data.
        data_object->execute();
    }
    
  2. 通过继承绑定数据和逻辑

    class Data{
    public:
        string some_values;
        ...
        virtual int execute() = 0;
    };
    
    class DataWithAlgoX : public Data{
    public:
        AlgoX_Relateddata algo_related_data; //some algo specific data (like state of algo)
        int execute();
    }
    
    class DataWithAlgoY : public Data{
    public:
        AlgoY_Relateddata algo_related_data; //some algo specific data (like state of algo)
        int execute();
    }
    
    some_function(){
        Data* data_object = create_data(algo_type); //A dummy function which creates an object of type data.
        data_object->execute();
    }
    
  3. 如果

    ,哪种设计更好
    1. 我们可以在数据algo->execute()的多次调用之间更改算法类型 (但转换不会非常频繁,只在某些特定情况下才需要) 有些人可能会指出,切换算法会让我们重新创建data_object。 如果架构 2 1 好得多,我们愿意承担额外的负担。

    2. 我们不会在数据algo->execute()的多次调用之间更改算法类型。

3 个答案:

答案 0 :(得分:1)

在(非常)不良实践中将数据和算法混合在同一个类中。 打破单一责任原则。

https://en.wikipedia.org/wiki/Single_responsibility_principle

如果要将多种类型的数据与多种算法结合使用 使用类似Mediator的东西。我们的想法是分别定义数据和算法,并在介体中定义它们之间的交互。

https://en.wikipedia.org/wiki/Mediator_pattern

在我看来,设计2比1更差。即使在设计1的情况下,我也会删除Data类中的算法引用。它只介绍高耦合,i。即这些类之间的依赖性使得受影响的一方受到另一方的影响:

https://en.wikipedia.org/wiki/Coupling_(computer_programming)

(和谷歌"低耦合,高凝聚力",这是另一个OOP原则)。

Mediator也会解决耦合问题。

答案 1 :(得分:0)

我更希望将Algo与Data分开。通常,相同的数据可以用于不同的Algo,同样的Algo可以用于不同的数据。因此,如果您将其作为继承实现,则可能导致代码重复或类似DataWithAgloA DataWithAlgoB等子类的组合爆炸。

更重要的是数据提供者,即生成数据的系统可能不需要知道在那里使用的复杂算法。生成数据可能是非常愚蠢的系统,可能有研究人员正在更新Algo。保持数据和Algo基本上违反了Single Responsible Principle。现在你的DataWithAlgo类有来自Algo和Data的2个变化轴(正如叔叔鲍勃所说)。

保持数据和Algo分离使代码保持灵活且易于更改并且还满足SRP。这减少了代码中的耦合,避免了任何组合爆炸。因此,我总是将Algo与数据分开。

答案 2 :(得分:0)

  

战略模式与继承

在这两者之间,优先于后者。在继承中,您不仅继承了API合同,而且还继承了行为,这可能会或可能无法覆盖。在您的情况下,由于您声明多个算法可能应用于同一个类今天但不一定明天,以这种方式应用继承会导致类的爆炸和重复的代码,如您所示。

然而,

  

我们有两种方法可以做到这一点

为什么?你考虑过Decorator Pattern(我最喜欢的)吗?根据数据节点的结构,甚至Visitor Pattern也许是有效的选择。

我还要提醒不要混淆"混合数据和算法始终打破SRP"建议一般抛出。你介绍" 2变化轴" 仅在用例实际出现时。理想情况下,如果您有完美的封装,那么类型无法处理并将算法应用于自己的数据。这取决于域名;在你的情况下,这显然不适用(似乎?)适用。