2014-04-11 32 views
0

假设我有一个名为BinaryClassifier的策略接口,可以采取Sample并返回一个double代表属于正类的Sample对象的概率:如何在STL容器中使用策略模式?

struct BinaryClassifier { 
    virtual ~BinaryClassifier(){} 
    virtual double classify(std::shared_ptr<Sample> sample) const = 0; 
}; 

我们可能有BinaryClassifier,例如几种实现,LogisticRegressionBinaryClassifier

Sample又一个接口只露出两个方法:

struct Sample { 
    virtual ~Sample() {} 
    InputFeatures const& get_input_features() const = 0; 
    double get_label() const = 0; 
}; 
从这两种方法

除了,的Sample具体实现暴露相当不同的接口(即,它们是不相关的),他们唯一的方面常见的是它们可以通过二元分类器进行分类。

到目前为止这么好。当我们决定引进BinaryClassifier::train方法出现

问题:

struct BinaryClassifier { 
    virtual ~BinaryClassifier(){} 
    virtual double classify(std::shared_ptr<Sample> sample) const = 0; 
    virtual void train(std::vector<std::shared_ptr<Sample>> samples) = 0; 
}; 

在这一点上,以下将不起作用:

std::vector<std::shared_ptr<ConcreteSample>> concreteSamples = ...; 
concreteBinaryClassifier.train(concreteSamples); 

这是因为std::vector<std::shared_ptr<ConcreteSample>>std::vector<std::shared_ptr<Sample>>是两个不相关的类型。

的C++ - ISH的解决办法是依靠模板:

 template<class SampleType> 
     virtual void train(std::vector<std::shared_ptr<SampleType>> samples) = 0; // non-working code, template method cannot be virtual 

但是模板方法不能virtual。不过,我希望BinaryClassifier是一个策略接口,因为可能存在许多BinaryClassifier实现。在这一点上,即使设计看起来很合理,我仍陷入死胡同。

编辑:此外,有可能发生对给定BinaryClassifier对象与ConcreteSampleA向量进行训练,而分类类型的对象ConcreteSampleB

这是模拟在大多数C这种情况的正确方法+用什么方式?

回答

0

你可以让你BinaryClassifier模板类

template<SampleType> class BinaryClassifier 
{ 
    virtual void train(std::vector<std::shared_ptr<SampleType>> samples) = 0; 
} 
+0

感谢您的回答,这是真的,但在这一点上,首先有'Sample'接口的原因是什么?而且,对于给定的'BinaryClassifier'对象可能发生的事情是'ConcreteSampleA'的向量来训练,同时对'ConcreteSampleB'类型的对象进行分类。 –

0

不能在ConcreteSampleA训练BinaryClassifier,然后用它来任何随机ConcreteSampleB分类。因此,样本类型是BinaryClassifier的固有部分。 Nullref的答案在这里是合理的:使样本类型成为模板参数。

正如您发现的那样,这意味着不再需要接口。好。 std::vector<int>不要求int也来自一些Element接口。

虽然你摆脱的东西,InputFeatures也看起来怀疑。我只是说get_input_features必须返回一些std::tuple其成员类型都有std::less定义。由于它不再是虚拟的,你不关心不同的样本类型返回不同的元组。我绝对不会硬编码get_label必须返回double。无论如何,这是一个奇怪的标签类型。

现在你已经说过,用样本类型A进行训练,然后对样本类型B进行分类可能是有意义的。这就是您进行优化的地方:似乎实际的兼容性要求是它们返回相同的元组。因此,Nullref的一个更好的解决方案是在get_input_sample返回的元组类型上对templatize BinaryClassifier

此外,classify不需要采取共同所有权。通过Sample const&train()真的应该只是一个迭代器对。 C++约定是传递一组对象作为范围。

+0

感谢您的回答。容器“容器”不要求“T”由任何特定的基类派生。然而,在这种情况下,我试图强制执行一个特定的要求:'BinaryClassifier'只知道如何处理'Sample'。 'InputFeatures'只是'Eigen :: RowVectorXd'的'typedef',所以它和你使用'std :: tuple'的建议非常相似。我将标签建模为“双”,因为它也可以是软标签。分类器不能仅仅通过要求输入特征是相同类型来训练,它仍然需要访问标签。 –

+0

@ burton0:当你说“BinaryClassifier只能处理样本”时,你的意思不是“它只能处理实现'get_input_features'和'get_label'的类吗?就像vector只能处理Movable和Assignable类?即需要方法,而不是基类。 – MSalters

+0

关于所有权你是完全正确的,我在SO编写了代码,但实际的代码使用引用。 'BinaryClassifier'只能处理实现'get_input_features'和'get_label'的类。您可以决定通过接口强制执行此操作,或者通过模板将其设置为需求。模板的问题在于您正在修复要使用的具体样本。相反,我想对任何样本进行“训练”和“分类”,而不管其具体实施。最后,'shared_ptr '的迭代器仍然不是'shared_ptr '的迭代器。 –