模块化:是否使用接口?

时间:2010-09-27 10:14:54

标签: c++ interface dependency-injection modularity

几年以来,常识似乎要求对接口进行编程而不是针对实现进行编程。对于高级代码,这似乎是合乎逻辑的,例如,如果我的应用程序中有一个复杂的求解器,那么最好有这样的东西:

ISolver *solver = solverFactory.getSolver();
solver->solve(inputdata);

而不是

Solver solver;
solver.solve(inputdata);

在第一个代码中,模拟求解器也更容易,因此,单元测试。

但我的问题是:在哪个级别使用界面不再有意义。例如。如果我的应用程序中有一个ComplexNumber类(或String类,或其他类),那么写下这个:

IComplexNumber *complexNumber = complexNumberFactory.create(1,2);   // 1+2i

似乎比写作更复杂(特别是关于表现):

ComplexNumber complexNumber(1,2);   // 1+2i

那么,哪些元素在决定是否应该将某些东西放在界面后面以及何时不应该放在界面后面时非常重要?

3 个答案:

答案 0 :(得分:3)

移动到界面的原因是它使事情更简单或减少耦合。 (这就是接口的用途)。

离开界面的原因是它会使事情变得更复杂或者会导致性能下降(但是可以确定的是配置文件)。我认为你的IComplexNumber类实际上使得类层次更复杂,除非你引入了MockComplexNumber,但是我怀疑这样的类会有用......而且它可能会让事情变得更慢,但我会测量它

但是,不要认为你需要以一种方式做所有事情,或者你的决定是固定不变的。使用界面进行转换非常容易。

答案 1 :(得分:1)

如果您将课程分为“服务”和“价值”课程,这取决于他们扮演的角色,那么答案很简单。仅在服务类上使用接口。在您的问题中,“求解器”是一种服务,“复数”是一个值。

使用new()应该很容易创建值类,因为它们只接受构造函数中的基本类型和其他值类。值类对模拟没有用,因为你可以使用真实的东西。

模拟服务类可能很有用,您可能需要多个实现。你的solverFactory可以返回一个naiveSolver,一个lookupSolver,一个GeneticSolver,一个mockSolver等。这里的界面很有用。

答案 2 :(得分:-2)

使用C ++并不重要,因为c ++具有多重继承,因此接口是一个可以添加实现的抽象类。我发现最常用的接口是具有单继承的Java和C#,如果你想要一个类来实现几个东西,那么只有一个可以是抽象类,其他的必须是接口