我有以下现有课程:
class Gaussian {
public:
virtual Vector get_mean() = 0;
virtual Matrix get_covariance() = 0;
virtual double calculate_likelihood(Vector &data) = 0;
};
class Diagonal_Gaussian : public Gaussian {
public:
virtual Vector get_mean();
virtual Matrix get_covariance();
virtual double calculate_likelihood(Vector &data);
private:
Vector m_mean;
Vector m_covariance;
};
class FullCov_Gaussian : public Gaussian {
public:
virtual Vector get_mean();
virtual Matrix get_covariance();
virtual double calculate_likelihood(Vector &data);
private:
Vector m_mean;
Matrix m_covariance;
};
如您所见,Gaussian类充当接口但没有任何实现。这一切都很好。
现在我想创建一个“AdaptedGaussian”类,其中在计算似然性之前,将改变提供给calculated_likelihood的数据向量。
一些要求:
我现在的想法是:
class Adapted_Gaussian : public Gaussian {
private:
Gaussian* m_g;
public:
virtual Vector get_mean() { return m_g->get_mean(); }
virtual Matrix get_covariance() { return m_g->get_covariance(); }
virtual double calculate_likelihood(Vector &data)
{
//do something with data
return g->calculate_likelihood(Vector &data);
}
}
可能存在一些缺点:
我是以正确的方式做到这一点的吗?或者有更好的方法来实现这个吗?
是否有一种很好的方法可以将每个未实现的方法标准委托给m_g的相同命名方法?
答案 0 :(得分:5)
看起来很好,我认为这是适配器模式的一个非常经典的实现。只是不要忘记为高斯类声明一个虚拟析构函数。至于缺点。
答案 1 :(得分:2)
正如您所指出的那样,编写大量基本的传递函数是繁琐的,并增加了隐含的维护开销。此外,具有指针成员意味着拥有指针的额外(尽管很简单)生命周期管理问题。解决这些问题的最简单方法可能是使AdaptedGaussian成为一个模板,模仿高斯的特定实例进行调整。
template<class BaseGaussian> class AdaptedGaussian : public BaseGaussian
{
virtual double calculate_likelihood(Vector &data)
{
// do something with data
return BaseGaussian::calculate_likelihood(Vector &data);
}
};
这确实依赖于高斯的所有适应实例都是默认可构造的,或者至少符合常见的构造函数签名。
如果您想从现有AdaptedGaussian
构建XXXGaussian
,那么只要XXXGaussian
本身是可复制的,您就可以添加合适的构造函数:
template<class BaseGaussian> class AdaptedGaussian : public BaseGaussian
{
public:
AdaptedGaussian(const BaseGaussian& other) : BaseGaussian(other)
{
}
// ...
};
答案 2 :(得分:1)
这也许可以通过Strategy Pattern来解决。
对我而言,duffymo也在朝这个方向思考“作曲”。以这种方式更改设计,基类调用它包含的其他对象的某些方法。该对象包含calculate_likelihood的编码。整个方法可以推迟或只修改(在第二种情况下,默认是不做任何事情)。
例如:(更正后的版本)
class Gaussian {
private:
Cl_Strategy* m_cl_strategy;
public:
Gaussian(Cl_Strategy* cl_strategy) {
m_cl_strategy = cl_strategy;
};
virtual Vector get_mean() = 0;
virtual Matrix get_covariance() = 0;
virtual double _calc_likelihood(Vector &data) = 0;
virtual double calculate_likelihood(Vector &data) {
m_cl_strategy->do_your_worst(this, data);
return _calc_likelihood(data);
};
};
我希望,我说得对,我的C ++有点拂尘......
_calc_likelihood必须由子类实现,calculate_likelihood一起绑定。
当然,这个解决方案会增加一些开销,但在某些情况下,开销可能没问题。
答案 3 :(得分:0)
在Java中,通常有一个接口和一个抽象类来实现它,以便为所有方法提供默认行为。 (请参阅Joshua Bloch在java.util包中设计的Collections API。)也许这也可以帮到你。您将为客户提供使用接口或抽象类的选择。
您也可以尝试composition。将一个改编的Gaussian实例传递给子类并将行为推迟到它。