ITK 中使用的其实是种称为 pluggable object factory 的设计模式,它可以在运行时进行动态替换,而且可以不修改已有代码的情况下添加处理新格式的图像文件类,等还有一些其它优点。它由两种模式组合而成:1.Abstract Factory 抽象工厂;2. Prototype 原型模式。还可能与单件模式(Singleton)组合。
简单的对象工厂可能如下所示:
1:
2: //Simple Factory
3: Circle
4: {
5: double radius;
6: }
7:
8: class Shape
9: {
10: public:
11: static Shape* newShape(istream&);
12: };
13: Shape* Shape::newShape(istream& params)
14: {
15: string className;
16: params >> className;
17: if (className == "Circle")
18: return new Circle(params);
19: else if (className == "Triangle")
20: return new Triangle(params);
21: else
22: //…
23: }
24:
Shape 是一个用来创建不同形状的对象工厂,Circle 是一种具体的形状。对象工厂 Shape 通过判断传入的参数,创建不同的对象实例。简单对象工厂的问题在于:1.基类 Shape 必须知道从它继承的每一个具体子类。2.当需要添加一种新的形状时,就得修改工厂方法 newShape()。这就违背了面向对象设计的“依赖倒置”原则(Dependency Inversion Principle),即高层模块不应该依赖于低层模块。同时还违背了“开-闭”原则(Opened-Closed),即 Open to extension,Closed to Modification。Pluggable Object Factory 模式可以解决这些问题。
Pluggable Object Factory,或者称为 PROTOTYPE–ABSTRACT FACTORY,可以将该模式归为创建型一类。
使用一个关联式容器如 map,关联容器中的每一个元素都是一个对象工厂,该对象工厂知道如何从一个抽象类层次结构中创建具体的子类对象实例。关联容器中的 key 则是用来从容器中查找合适的对象工厂。
Prototype Factory Compound Pattern:使用工厂方法,我们创建一个抽象类 ShapeMaker,它有一个静态的公有方法 newShape。一个具体的 CircleMaker 知道如何创建 circle 对象,它继承自 ShapeMaker。
1: //
2: class ShapeMaker
3: {
4: public:
5: static Shape* newShape(istream&);
6: protected:
7: typedef map<string,ShapeMaker*> MakerMap;
8: virtual Shape* makeShape(istream&) const=0;
9: static MakerMap registry;
10: };
11: Shape* ShapeMaker::newShape(istream& is) {
12: string className;
13: is >> className;
14: ShapeMaker* maker =
15: (*registry.find(className)).second;
16: return maker->makeShape(is);
17: }
18: //
19: class CircleMaker : public ShapeMaker
20: {
21: private:
22: Shape* makeShape(istream& params) const
23: {
24: return new Circle(params);
25: }
26: };
27:
1:
2: //
3: class CircleMaker : public ShapeMaker
4: {
5: private:
6: CircleMaker() : ShapeMaker("Circle") {}
7: static const CircleMaker registerThis;
8: };
9: //其中:
10: ShapeMaker::ShapeMaker(string className)
11: {
12: //在基类的静态关联容器中注册自己
13: registry.insert( make_pair(className, this) );
14: }
15: //使用:
16: fstream params("shapes.txt");
17: Shape* shape = ShapeMaker::newShape(params);
18:
Plugging in with Prototype Factory:Factory Method 工厂方法与 Prototype 原型模式结合,允许工程扩展 ShapeMaker可以创建对象的 Shape 类型。ShapeMaker 类以及与其协作的其它类表示了 Prototype Factory 模式。Factory Method 工厂方法提供创建对象实例的方法,Prototype 原型模式提供在运行时动态注册对象工厂的方法。
1.GENERIC FACTORIES 泛化工厂:从上面的 Prototype Factory 模式可以看出,算法与数据类型是相互独立的,所以我们使用模板实现 Prototype Factory 组合模式:
1:
2: //Generic 工厂
3: template<class Object>
4: class Maker
5: {
6: public:
7: virtual ~Maker();
8: static Object* newObject(istream&);
9: protected:
10: Maker(const string& className);
11: virtual Object* makeObject(istream&) const=0;
12: private:
13: typedef Maker* MakerPtr;14: typedef map<string,MakerPtr> MakerMap;15: static MakerMap registry;16: };
17:
这样,ShapeMaker 便可如下重写:
1: //2: template<class Shape>3: class ShapeMaker : public Maker4: {
5: protected:6: ShapeMaker(const string& className)7: : Maker (className) {}
8: };
9: class CircleMaker : public ShapeMaker10: {
11: private:12: CircleMaker () : ShapeMaker ("Circle") {}13: Shape* makeObject(istream& params) const {14: return new Circle(params); }15: static const CircleMaker registerThis;16: };
17:
还可以很容易地创建其它对象工厂的抽象类层次,如下:
1: //2: template<class CoordSys>3: class CoordSysMaker : public Maker4: {
5: //…6: };
7: class XyzMaker : public CoordSysMaker8: {
9: //…10: };
11: class RasterMaker : public CoordSysMaker12: {
13: //…14: };
15:
Making Objects from Files:有时我们可能不使用 C++ 的 istream 流作为 newObject() 的参数,而想使用 FILE*,我们可以将 Maker 的模板参数如下修改即可:
1: //2: template <class Object, class Params>3: class Maker4: {
5: public:6: static Object* newObject(Params);7: protected:8: typedef Maker * MakerPtr;
9: virtual Object* makeObject(Params) const=0;10: };
11: //12: class ShapeMaker13: : public Maker14: {
15: //...16: };
17: class LegacyShapeMaker18: : public Maker19: {
20: //…21: };
22:
Making Objects from Aggregate Classes:我们还可以从一个包含某个具体子类数据成员的聚集类构造对象:
1: //2: class GeomModel3: {
4: //...5: private:6: const char* sensorName;7: FILE* geomFile;
8: const char* outputDir;9: };
10: //结构体,用于传递构造 GeomModel 所需的参数11: struct GeomModelParams12: {
13: const char* sensorName;14: FILE* geomFile;
15: const char* outputDir;16: };
17: class GeomModelMaker18: : public Maker19: {
20: //…21: };
22:
2.Chain of Factories:如果我们要创建的对象的类型不是流的第一个元素,那么上面的工厂就会失效。我们可以通过将职责链模式(Chain of Responsibility)组合到我们 Pluggable 工厂模式来解决这个问题。职责链模式允许我们顺序迭代一个 Makers 链表,让 makers 决定哪一个 maker 可以创建该对象。在职责链上通用的查找机制可能如下:
1: //2: Object* Maker
3: ::newObject(Params params)4: {
5: Object* object = 0;6: for (const_iterator iter = registry.begin();7: !object && iter != registry.end(); ++iter )8: {
9: MakerPtr maker = (*iter).second;
10: object = maker->makeObject(params);11: }
12: return object;13: }
14:
3.PRIORITIZING FACTORIES,优先工厂:前面我们一直都在使用关联容器 map 存储 key 与 对象工厂之间的连系,我们知道 map 中的 key 是唯一的,也就是说我们前面假定了 key(params) 与 对象工厂(maker)之间存在 1-1 的关系。但实际中经常可能会出现不只有一个对象工厂可以创建某个对象,这时我们只需要将 map 改成 multimap,并在创建对象时设置一定的优先策略即可。其中,ITK 中的对象工厂使用的便是 multimap,一个对象可能会有多个工厂可以创建。
我们创建一个新类 PriorityMaker 表示优化查找策略,它从对象工厂列表中查找可以创建指定对象优先级最高的对象工厂:
ITK 中的策略是:在 multimap 中查找可以创建 className 的对象工厂,然后选择第一个对象工厂进行创建。ITK 中还提供了一个方法,该方法会使用所有可以创建 className 的对象工厂,依次创建出所有的对象实例。1: //Priority Factory2: template <class Object>3: class PriorityMaker4: : public Maker5: {
6: public:7: static Object* newObject(istream& params)8: {
9: string className;10: params >> className;11:
12: //定位第一个可以创建 className 对象的对象工厂13: const_iterator iter = registry.lower_bound(className);
14:
15: //继续在 multimap 中查找,直至某个对象工厂不能创建 className 对象实例16: //并进行简单的比较,选择优先级最高的对象工厂17: const_iterator tmp = iter;
18: while ( ++tmp != registry.end() &&19: (*tmp).first == className)
20: {
21: if (*(*iter).second < *(*tmp).second)22: iter = tmp;
23: }
24:
25: //最后使用选择到的对象工厂创建对象实例26: MakerPtr maker = (*iter).second;
27: return maker->makeObject(params);28: }
29: }
30:
4.SINGLETON FACTORIES,单件工厂:当我们只有一个选择的时候,会需要单件工厂,就如同单件对象一样。单件工厂的查找策略非常简单,因为在某一时间只有一个对象工厂会被注册。如果发生不止一个对象工厂被注册的错误,我们原则是:使用最后一个注册的对象工厂。
1: //Singleton Factory2: template <class Object>3: class SingletonMaker : public Maker void>4: {
5: public:6: static Object* newObject()7: {
8: //rbegin:如果出现多个工厂注册的错误,我们选择最后一个9: MakerPtr maker =
10: (*registry.rbegin()).second;
11: return maker->makeObject();12: }
13: protected:14: SingletonMaker()
15: : Maker void>( "SingletonMaker"){}16: };
17:
- 顶
- 0
- 踩
- 0
jackap: 图片看不到了,可以修复下吗?
aaaa_1111_: 楼主,您好!请问ITK中的三维配准有什么要求吗?DeformableRegistration8中优化...
jamesLBJ: 楼主你好,请问ITK怎么读.mhd和.raw格式的?还是只能用vtk来读取?
lj695242104: cmake 在ubuntu下gui?您说的按箭头操作根本就没出现啊!求解?
u014376282: ITKIO不存在啊
u011683778: 怎么没有 霹雳震寰宇之龙战八荒?
u011472090: 我也是山西人,小时候没看完,现在网上的资源不太给力,模糊,没有国语的
TonyShengTan: 正在编译中,不过cmake'提示Performing Test CXX_HAS_WARNING-Wf...
thfeathers: 不得在任何场合表达与公司有关的信息,给你个一级违规
gfhhgf: 这是一个itk自带的例子吧