我正在重新设计一个我拥有的图书馆 目前我有一套算法,它们不以任何方式相互关联。
我的目标是让所有具体算法实现一个大致由Init()
和Run(In,Out)
组成的接口,以便我可以按以下方式执行它们:
void Process()
{
// IAlgotrithm* algX = new CAlgX(); X:{A,B,C}
IAlgorithm* algs[] = { algA, algB, algC };
for (int i=0; i < 3; i++) {
algs[i]->Init(...);
algs[i]->Run(In,Out);
}
}
问题是,目前每个算法都接受一个不同的结构作为其输入参数
例如,CAlgA
有一个方法Init(CAlgAParameter param)
,其中CAlgAParameter
是一个结构,其中包含特定于AlgA的字段。每种算法都有自己的结构,由不同类型的完全不同的字段组成。
解决这个问题的最佳方式是什么?
我能想到的一个选项是拥有一个包含与所有算法相关的所有参数的地图,并将初始化输入结构的工作委托给算法。也就是说,算法的客户端将不知道具体的输入结构是什么样的 - 基于映射中的所有全局参数来创建其输入结构将是算法工作。我不喜欢这个想法,因为它无法在编译时检查并且容易出错。
最好的方法是什么?
谢谢
答案 0 :(得分:5)
为什么不在构造期间初始化,只需在循环中调用Run()
?因此,在构造中,您可以使用户有责任为给定的算法提供正确的配置,即
IAlgorithm* algs[] = { new CAlgA(CAlgAParameter(...)), new CAlgB(CAlgBParameter(...)), new CAlgC(CAlgCParameter(...)) };
//loop
使用例外来处理算法的错误配置。
答案 1 :(得分:0)
对于不会被任何算法更改的静态参数,基于构造函数的初始化很好。每次运行算法必须提供的控制参数可以由每个算法的接口(或所有抽象方法的抽象类)指定。
public class IAlg1ControlParams {
public:
virtual ~IAlg1ControlParams () {}
virtual int getParam1() = 0;
virtual void setParam2(char val) = 0;
}
这将使您的算法占用空间尽可能小。这些接口对于测试算法也很有用,因为您只需要在测试中提供两个接口的实现,而不是使用字符串键的一些大型参数映射。使用像Google Mock这样的模拟框架可以做得更好。
public void WhenInputIs10_Algorithm1SetsParam2Tob() {
Alg1 alg1 = new Alg1("Test data", 10);
IAlg1ControlParams context = new MockAlg1ControlParams(10);
alg1.Run(context);
assert(context.getParam2() == 'b');
}
然后,您可以拥有一个上下文或状态对象,为每组需要执行的算法实现接口。这将确保您有编译时检查参数字段和方法是否存在。此外,如果您需要数据从一种算法流向另一种算法,则使用相同的上下文对象将确保将更新的数据提供给管道中的后续算法。
public class AlgSet1Context: public IAlg1Context, public IAlg2Context...
在每个算法中,您需要验证控制参数中的值。我建议在这里使用模板方法模式,因此您有一个基本业务规则,它提供Run(ControlParams)
的非虚拟实现,并调用两个受保护的虚拟方法Verify(ControlParams)
和Execute(ControlParams)
。这将确保所有在以后实施新算法的开发人员都知道他们必须验证控制参数。