c – 面向对象还是顺序?

我在main()中重构了500行C代码来求解微分方程.我想把我们的求解器的重要思想封装成更小的函数(即“SolvePotential(…)”而不是50行的数字代码).

我应该用一堆函数来编写这个序列,这些函数需要非常长的参数列表,例如:

int main(int *argc, void **argv){
   interpolate(x,y,z, x_interp, y_interp, z_interp, potential, &newPotential);
   compute_flux(x,y,z, &flux)
   compute_energy(x,y,z, &eng)
   ...
   // 10 other high-level function calls with long parameter lists
   ...
   return 0;
}    

或者我应该创建一个像这样调用的“SolvePotential”类:

int main(int *argc, void **argv){
   potential = SolvePotential(nx, ny, nz, nOrder);
   potential.solve();
   return 0;
}

我将在SolvePotential中定义使用成员变量而不是长参数列表的函数,例如:

SolverPotential::solve(){
  SolvePotential::interpolate()
  SolverPotential::compute_flux()
  SolverPotential::compute_energy()
  // ... 
  //  10 other high-level function calls with NO parameter lists (just use private member variables)
}

在任何一种情况下,我都怀疑我会非常重复使用这些代码……实际上,我只是在重构以帮助提高代码清晰度.

也许这就像争论“它是’12’还是’打了十几个’?”,但你怎么看?

最佳答案
都不是. “将我的所有代码从一个单独的函数移动到一个单独的类”不是OOP. OOP的基本规则之一是一个班级应该只有一个责任区.
这不是一个单一的责任,大概是15:

SolverPotential::solve(){
SolvePotential::interpolate()
SolverPotential::compute_flux()
SolverPotential::compute_energy()
// ... 
//  10 other high-level function calls with NO parameter lists (just use private member variables)
}

这也使得维持类不变量几乎是不可能的,不是吗?什么时候调用compute_flux有效?解决?插?什么阻止我以错误的顺序做这件事?如果我这样做,班级是否会处于有效状态?我会从中获得有效数据吗?

但是,为什么它是 – 或者?为什么不能创建多个类和函数?

// This struct could be replaced with something like typedef boost::tuple<double,double,double> coord3d
struct coord3d {
double x, y, z;
};

coord3d interpolate(const coord3d& coord, const coord3d& interpolated, double potential); // Just return the potential, rather than using messy output parameters
double compute_flux(const coord3d coord&flux); // Return the flux instead of output params
double compute_energy(const coord3d& coord); // And return the energy directly as well

当然,这些功能不一定是功能.如果必要/方便的话,每个都可以成为一个类,或者可能更好的是一个函子,以保持必要的状态,并且可能允许你将它们作为参数有效地传递给其他函数.

如果最佳性能很重要,您可能必须小心直接返回较大的结构,而不是使用输出参数,但我肯定首先要查看它是否是一个问题,即使它是,你可能可以避免使用表达模板输出参数.

如果你有一个可以执行许多独立操作的概念对象,它可能暗示你需要一些OOP,它应该被建模为具有许多成员函数的类,每个当然都维护类无论如何,何时以及为何被召唤,都是不变的.

如果您需要编写许多函数,将它们粘合在一起以形成新的,更大的功能,函数编程和函子很可能就是您所需要的.期望可组合函数的一个常见原因(但绝对不是唯一的)是,如果您需要在许多不同的数据集上执行相同的操作(甚至可能是几种不同的类型,都实现相同的概念).使编译器完成繁重的操作允许它与std :: transform或std :: for_each一起使用.
您可能还希望使用currying来逐步组合函数(也许某些函数可以使用一组固定参数进行参数化,这些参数在调用之间不会有所不同).再次,创建一个使用这些固定参数初始化的仿函数,然后在operator()中提供变化的数据.

最后,如果您只需要对某些可变数据执行一系列操作,那么普通的旧程序编程可能最适合您的需求.

最后,使用泛型编程,模板化必要的类和函数,以允许它们一起工作,而不必跳过像指针间接或继承这样的箍.

不要太忙于OOP.使用您可以使用的工具.

我不确定你的问题的背景是否足够肯定,但在我看来,你真正需要的不是一个类,它只是一个功能层次结构.
您的用户代码调用solve(). solve()内部调用,例如(为了示例而构成),interpolate()和compute_energy(). compute_energy()在内部调用compute_flux(),依此类推.每个函数只进行几次调用以执行构成函数职责的逻辑步骤.所以你没有一个庞大的课程,有十几个不同的职责,或者一个巨大的单片功能,它按顺序完成所有事情.

在任何情况下,“非常长的参数列表”都没有错(你通常可以通过将它们中的一些组合在一起来缩短它们,但即使你不能,也没有关于传递大量参数的“un-OOP”相反,它意味着函数很好地封装了其他所有东西.它所需要的只是在参数中传递,因此它并没有真正与应用程序的其余部分相关联.

转载注明原文:c – 面向对象还是顺序? - 代码日志