gpt4 book ai didi

c++ - 这是使用抽象工厂模式的示例吗?

转载 作者:太空狗 更新时间:2023-10-29 21:15:11 25 4
gpt4 key购买 nike

现在我正在开发一个识别照片中物体的类,这个类由几个组件(类)组成。例如,

class PhotoRecognizer
{
public:
int perform_recogniton()
{
pPreProcessing->do_preprocessing();
pFeatureExtractor->do_feature_extraction();
pClassifier->do_classification()
}

boost::shared_ptr<PreProcessing> pPreProcessing;
boost::shared_ptr<FeatureExtractor> pFeatureExtractor;
boost::shared_ptr<Classifier> pClassifier;

}

在这个例子中,当我们使用这个类进行识别时,我们调用其他类PreProcessing , FeatureExtractorClassifier .正如您所想象的那样,有许多不同的方法可以实现每个类。例如,对于 Classifier类,我们可以使用 SVMClassfierNeuralNetworkClassifer , 这是基本类的派生类 Classifier类(class)。

class SVMClassifier: public Classifier
{
public:
void do_classification();

};

因此,通过在 PhotoRecognizer 中使用不同的元素类,我们可以创建不同种类的PhotoRecongnizer .现在,我正在构建一个基准以了解如何将这些元素组合在一起以创建最佳 PhotoRecognizer .我能想到的一种解决方案是使用抽象工厂:

class MethodFactory
{
public:
MethodFactory(){};
boost::shared_ptr<PreProcessing> pPreProcessing;
boost::shared_ptr<FeatureExtractor> pFeatureExtractor;
boost::shared_ptr<Classifier> pClassifier;

};
class Method1:public MethodFactory
{
public:
Method1():MethodFactory()
{
pPreProcessing.reset(new GaussianFiltering);
pFeatureExtractor.reset(new FFTStatictis);
pClassifier.reset(new SVMClassifier);

}

};

class Method2:public MethodFactory
{
public:
Method1():MethodFactory()
{
pPreProcessing.reset(new MedianFiltering);
pFeatureExtractor.reset(new WaveletStatictis);
pClassifier.reset(new NearestNeighborClassifier);

}

};



class PhotoRecognizer
{
public:
PhotoRecognizer(MethodFactory *p):pFactory(p)
{
}
int perform_recogniton()
{
pFactory->pPreProcessing->do_preprocessing();
pFactory->pFeatureExtractor->do_feature_extraction();
pFactory->pClassifier->do_classification()
}

MethodFactory *pFactory;


}

所以当我使用Method1进行照片识别时,我可以简单地做如下操作:

Method1 med;
PhotoRecognizer recogMethod1(&med);
med.perform_recognition()

更进一步,我什至可以上课PhotoRecognizer更紧凑:

enum RecMethod
{
Method1, Method2

};

class PhotoRecognizer
{
public:
PhotoRecognizer(RecMethod)
{
switch(RecMethod)
{
case Method1:
pFactory.reset(new Method1());
break;
...
}
}

boost::shared_ptr<MethodFactory> pFactory;

};

所以这是我的问题:抽象工厂设计模式在上述情况下是否合理?有替代解决方案吗?谢谢。

最佳答案

因为通常没有最终的“正确”方法来做到这一点,答案在很大程度上取决于项目的使用方式。因此,如果它只是为了快速测试,只做一次,从不回头看 - 如果您内心渴望,请继续使用枚举,没有人应该阻止您。

但是,如果您打算随着时间的推移扩展可能的方法,我不鼓励使用枚举的第二种方法。原因是:每次你想添加一个新方法时,你都必须更改 PhotoRecognizer 类,所以你必须阅读代码,记住它在做什么以及是否应该由其他人来做 - 它会花更多的时间。

带有枚举的设计违反了 SOLID 的两个首要规则 (https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)):

  1. 开闭原则 (OCP):PhotoRecognizer 类在不修改其代码的情况下无法扩展(添加新方法)。
  2. 单一责任原则 (SRP):PhotoRecognizer 类不仅可以识别照片,还可以作为方法工厂。

您的第一种方法更好,因为如果您要定义另一个 Method3,您可以将其放入您的 PhotoRecognizer 并在不更改类代码的情况下使用它:

 //define Method3 somewhere
Method3 med;
PhotoRecognizer recogMethod3(&med);
med.perform_recognition()

我不喜欢您的方法的一点是,您必须为每种可能的组合编写一个类 (MethodX),这可能会导致很多乏味的工作。我会做以下事情:

struct Method
{
boost::shared_ptr<PreProcessing> pPreProcessing;
boost::shared_ptr<FeatureExtractor> pFeatureExtractor;
boost::shared_ptr<Classifier> pClassifier;
};

Method看成是不同算法的slot的集合,放在这里是因为这样传递Processing/Extractor/Classifier很方便。

并且可以使用工厂函数:

   enum PreprocessingType {pType1, pType2, ...};
enum FeatureExtractorType {feType1, feType2, ..};
enum ClassifierType {cType1, cType2, ... };

Method createMethod(PreprocessingType p, FeatureExtractionType fe, ClassifierType ct){
Method result;
swith(p){
pType1: result.pPreprocessing.reset(new Type1Preprocessing());
break;
....
}
//the same for the other two: fe and ct
....
return result
}

您可能会问:“但是 OCP 呢?” - 你是对的!必须更改 createMethod 以添加其他(新)类。如果您仍然可以手动创建 Method 对象,使用新类初始化字段并将其传递给 PhotoRecognizer-构造函数。

但是使用 C++,您可以使用一个强大的工具 - 模板:

   template < typename P, typename FE, typename C>
Method createMethod(){
Method result;
result.pPrepricessing.reset(new P());
result.pFeatureExtractor.reset(new FE());
result.pClassifier.reset(new C());
return result
}

并且您可以自由选择任何您想要的组合而无需更改代码:

 //define P1, FE22, C2 somewhere
Method medX=createMethod<P1, FE22, C2>();
PhotoRecognizer recogMethod3(&med);
recogMethod3.perform_recognition()

还有一个问题:如果 PreProcessingA 类不能与 ClassifierB 类一起使用怎么办?早些时候,如果没有 MethodAB 类,则没有人可以使用它,但现在可能会出现这种错误。

要处理这个问题,可以使用特征:

template <class A, class B>
struct Together{
static const bool can_be_used=false;

template <>
struct Together<class PreprocessingA, class ClassifierA>{
static const bool can_be_used=true;
}

template < typename P, typename FE, typename C>
Method createMethod(){
static_assert(Together<P,C>::can_be_used, "classes cannot be used together");
Method result;
....
}

结论

这种方法有以下优点:

  1. SRP,即 PhotoRecognizer - 仅识别,Method - 仅捆绑算法部分,createMethod - 仅创建方法。
  2. OCP,即我们可以在不更改其他类/函数代码的情况下添加新算法
  3. 多亏了特征,我们可以在编译时检测到部分算法的错误组合。
  4. 没有样板代码/没有代码重复。

附言:

您可能会说,为什么不从头开始整个 Method 类?也可以使用:

   template < typename P, typename FE, typename C>
PhotoRecognizer{
P preprocessing;
FE featureExtractor;
C classifier;
...
}

PhotoRecognizer<P1, FE22, C2> recog();
recog.perform_recognition();

是的,这是真的。这种选择有一些优点和缺点,必须对项目有更多了解才能做出正确的权衡。但默认情况下,我会采用更符合 SRP 原则的方法,将部分算法封装到 Method 类中。

关于c++ - 这是使用抽象工厂模式的示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38621335/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com