- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
现在我正在开发一个识别照片中物体的类,这个类由几个组件(类)组成。例如,
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
, FeatureExtractor
和 Classifier
.正如您所想象的那样,有许多不同的方法可以实现每个类。例如,对于 Classifier
类,我们可以使用 SVMClassfier
或 NeuralNetworkClassifer
, 这是基本类的派生类 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)):
PhotoRecognizer
类在不修改其代码的情况下无法扩展(添加新方法)。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;
....
}
结论
这种方法有以下优点:
PhotoRecognizer
- 仅识别,Method
- 仅捆绑算法部分,createMethod
- 仅创建方法。附言:
您可能会说,为什么不从头开始整个 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/
我应该执行以下操作: 可能通过服务/工厂,使用 $q(异步)查询 API 以获取大型名称数据集 有另一个服务(也是异步的),它应该只返回上述工厂的元素,如果它们与某个字符串(搜索字段)匹配。目的是缩小
我有一个通用的基类。我有一个实现基类的具体类。 我将如何创建工厂类/方法来交付不同类型的具体类? 举个例子: public class ReceiverBase where T : IInte
我正在查看以下链接中的 Ninject Factory 扩展: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-intro
工厂、提供商和服务这三个术语之间有什么区别? 刚刚了解 NHibernate 及其存储库模式(POCO 类等)。 最佳答案 工厂:通过将一堆位组合在一起或基于某种上下文选择类型来组装类 Provide
使用CGLIB我可以做到 final var enhancer = new Enhancer(); enhancer.setUseCache(false); enhancer.setSuperclas
我试图在 Kotlin 中使用伴随对象工厂方法(相当于 Java 中的静态工厂方法)创建一个嵌套内部类。这是我的代码的简化版本。 class OuterClass { var myData:L
我正在为我的大学做一个项目,但遇到了问题。 基本上,该项目由一个客户端-服务器应用程序组成,我想创建一个用于通信的 Packet 类。数据包由 header 和主体组成。现在问题来了。我可以有一些不同
这个问题在这里已经有了答案: Why doesn't polymorphism work without pointers/references? (6 个答案) What is object sl
我正在制作一个套接字工厂。我希望每个外部应用程序都使用 Socket 类的接口(interface),它是几个类(ServerSocketTCP、ClientSocketTCP、ServerSocke
我是 angularjs 的新手,我正在尝试创建一个小型电影数据库。这是我第一次使用工厂,我想确保这是正确的方法,以及如何在另一个功能中使用这个工厂,如下所示? 我希望这个工厂只运行一次,这样我就可以
这个问题在这里已经有了答案: Java inner class and static nested class (28 个答案) 关闭 5 年前。 public class DataFactory
我看过很多关于 C++ 工厂的帖子,但到目前为止我还没有看到解决我的问题的解决方案。 (虽然我可能遗漏了一些东西。) 示例控制台应用程序: #include #include #include
这是一个简单的 C++ 项目,有 2 种设计模式:单例和工厂,sigleton 也是一个模板化类,一个接口(interface) (IHash) 和一个类 (Hash1)。一个简单的工厂类 (Hash
这个问题类似于Factory and generics ,并且可能有相同的答案,但它是不同的。我有一个通用基类,它将由完全独立的 JAR 中的类进行扩展。所述 JAR 应该能够在不更改任何其他代码的情
问题是我需要为传递的类创建一个新实例 有没有办法重写这个函数,让它可以接受任意数量的参数? function createInstance(ofClass, arg1, arg2, arg3, ...
我想用简单的 C++ 语法创建一个简单的工厂方法: void *createObject(const char *str,...) { if(!strcmp("X",str)) retu
经过大约 10 个月的程序化 PHP 学习后,我现在正尝试着手研究基本的 OOP 原则和设计模式。这是一个爱好,我没有那么多时间去追求它,所以请原谅这个问题的水平很低。 我的网站(目前 100% 程序
我有一个简单的问题。 我如何编写一个工厂来定义使用 make() 或 create() 的关系,具体取决于原始调用 make() 还是 create()? 这是我的用例: 我有一个简单的工厂 /**
我正在尝试在延迟加载模块中提供 APP_BASE_HREF 注入(inject) token ,然而,工厂方法根本没有被调用。 在这里https://github.com/MaurizioCascia
我有以下 ast: import { factory as f } from 'typescript' const typeDeclaration = f.createTypeAliasDeclara
我是一名优秀的程序员,十分优秀!