我们有一些算法适用于某些数据,算法可能会在同一数据上多次应用。我们有两种方法可以做到这一点:
保持数据和逻辑分离
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();
}
通过继承绑定数据和逻辑
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();
}
如果
,哪种设计更好我们可以在数据algo->execute()
的多次调用之间更改算法类型
(但转换不会非常频繁,只在某些特定情况下才需要)
有些人可能会指出,切换算法会让我们重新创建data_object
。
如果架构 2 比 1 好得多,我们愿意承担额外的负担。
我们不会在数据algo->execute()
的多次调用之间更改算法类型。
答案 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变化轴" 仅在用例实际出现时。理想情况下,如果您有完美的封装,那么类型无法处理并将算法应用于自己的数据。这取决于域名;在你的情况下,这显然不适用(似乎?)适用。