我想设计一个通用的C ++类,它定义一个operator()
函数,它返回一个点上的数学函数的值。但是,我希望该类能够使用已定义operator()
的对象或使用该类将插值以提供值的值表来实例化。我想到了以下方法:
class MathFunction
{
MathFunction(Functor& function);
MathFunction(Mat<double> interpolationValues);
double operator()(double radius, double angle);
};
构造函数可以设置成员变量,而double operator()
可以使用switch语句来确定如何输出我想要的double
。但这看起来非常不优雅。
这个类的模板化版本可能有用,但由于这两个方法不共享任何代码,这样做是否明智?模板版本究竟是如何设计的?
不确定我是否清楚。如果需要澄清,请发表评论。
编辑:虽然我选择了Useless的答案来完整,但我想强调dasblikenlight的贡献的速度和清晰度。谢谢。
答案 0 :(得分:6)
这是使用strategy pattern的主要情况:根据传递给构造函数的参数,MathFunction
应该实例化依赖于Functor
的策略对象或策略对象依赖于插值的列表。然后operator ()
的调用应该将调用转发给策略,并通过公共虚函数的实现获得结果:
class MathFunction {
struct Strategy {
virtual double Calculate(double radius, double angle)=0;
virtual ~Strategy(){}
};
class FunctorStrategy : public Strategy {
Functor& _function;
public:
FunctorStrategy(Functor& function) : _function(function) {}
virtual double Calculate(double radius, double angle) {
return _function(radius, angle);
}
}
class InterpolationStrategy : public Strategy {
Mat<double> _interpolationValues;
public:
InterpolationStrategy (Mat<double> interpolationValues)
: _interpolationValues(interpolationValues) {}
virtual double Calculate(double radius, double angle) {
return ...; // Use _interpolationValues to do calculation
}
};
unique_ptr<Strategy> _strategy;
public:
MathFunction(Functor& function)
: _strategy(new FunctorStrategy(function)) {}
MathFunction(Mat<double> interpolationValues)
: _strategy(new InterpolationStrategy(interpolationValues)) {}
// And now for the complicated part:
double operator()(double radius, double angle) {
return _strategy->Calculate(radius, angle); // TA-DA!!!
}
};
答案 1 :(得分:1)
但由于这两种方法不共享任何代码,因此这样做是否明智 它?
如果通过operator()生成输出的方式不是通过这两种机制协同进行的,我认为将它们放在一个类中并不是一个好主意。我会说这违反了单一责任原则a.k.a SRP。
相反,请尝试使用Strategy Design Pattern将功能分配到两个单独的策略类中。然后可以在策略上模板化您的课程
答案 2 :(得分:1)
如果MathFunction
没有任何常见的实现,它的用途是什么?
如果其目的是为两个实现提供通用接口,请考虑使用它的位置:
MathFunction
的类型,或者代码中始终静态地知道它使用的是哪种类型在案例1中,使用策略模式之类的东西是合理的。 MathFunction
可以是调度到虚拟策略的静态类型包装器,也可以编写抽象的MathFunction基类,并实例化两个具体子类中的一个。
dasblinkenlight 已经演示了策略版本,所以这里是ABC等价物(请注意它如何使用工厂函数来隐藏实现细节)
// public header
class MathFunction {
public:
virtual ~MathFunction() {}
virtual double operator() (double radius, double angle) = 0;
};
MathFunction* make_function(Functor& function);
MathFunction* make_function(Mat<double> interpolationValues);
// implementation
class FunctorMathFunction : public MathFunction {
Functor& _function;
public:
FunctorMathFunction(Functor& function) : _function(function) {}
virtual double operator() (double radius, double angle) {
return _function(radius, angle);
}
};
class TableMathFunction : public MathFunction {
Mat<double> _interpolationValues;
public:
TableMathFunction (Mat<double> interpolationValues)
: _interpolationValues(interpolationValues) {}
virtual double operator() (double radius, double angle) {
return ...; // Use _interpolationValues to do calculation
}
};
MathFunction* make_function(Functor& function) {
return new FunctorMathFunction(function);
}
MathFunction* (Mat<double> interpolationValues) {
return new TableMathFunction(interpolationValues);
}
在案例2中,模板化MathFunction
是一个不错的选择:您可以(部分地)对其进行专门化,或者使用策略模式的编译时等效项,即在Policy类上参数化MathFunction,它委托评估。如果考虑性能,保存虚拟函数调用(并启用内嵌)可能很有用。
template <typename EvaluationPolicy>
class MathFunction
{
EvaluationPolicy eval;
public:
MathFunction() {}
MathFunction(EvaluationPolicy const &ep) : eval(ep) {}
double operator() (double radius, double angle) {
return eval.calc(radius, angle);
}
};
class FunctionPolicy
{
std::function<double(double,double)> func;
public:
FunctionPolicy(std::function<double(double,double)> f) : func(f) {}
double calc(double r, double a) { return func(r, a); }
};
class TablePolicy
{
Mat<double> mat;
public:
TablePolicy(Mat<double> values) : mat(values) {}
double calc(double r, double a) { return ....; }
};
使用策略而不是编写两个不同的具体类(FunctionMathFunction
和TableMathFunction
)的好处在于显示它们之间的关系,共享不的任何代码取决于政策,以及将不相关的问题分成单独的政策的能力。
答案 3 :(得分:0)
我不确定您的代码的模板版本是否真的是对设计的改进。正如你所指出的那样,主要问题是你在这里有两个已完成的不同机制,这些机制被捆绑在一起成为一个类。使模板与模板一起使用的一种方法是,您实际上创建了两个专用模板,其中一个是采用函数的案例的专门化,另一个是采用表格。我不相信这是正确的机制。
除非您可以通过分析验证您绝对肯定无法忍受虚函数调用的开销,否则我会选择运行时多态而不是编译时多态,并将您的MathFunction
类转换为提供纯虚operator()
,然后从中导出两个实现,一个处理函数案例,另一个处理表格案例。
答案 4 :(得分:0)
你可以在这里使用多态:
class MathFunction
{
private:
class Impl
{
public:
virtual ~Impl() {}
virtual double compute(double radius, double angle) = 0;
};
class FunctorImpl : public Impl
{
public:
explicit FunctorImpl(Functor & function);
double compute(double radius, double angle);
};
class MatImpl : public Impl
{
public:
explicit MatImpl( Mat<double> interpolationValues);
double compute(double radius, double angle);
};
std::unique_ptr< Impl > impl;
public:
MathFunction(Functor& function) : impl( new FunctorImpl( function ) ) {}
MathFunction(Mat<double> interpolationValues) : impl( new MatImpl( interpolationValues ) ) {}
double operator()(double radius, double angle)
{
return impl->compute( radius, angle );
}
};