rambo

工厂模式

工厂模式是一个创建型的设计模式。它允许创造对象时不指定要创建的对象的具体类型。本质上工厂方法就是构造函数的一般化。首先回归一下,C++中构造函数的几个限制:

  • 没有返回值。意味着在对象初始化期间不能通过返回NULL指针发出错误信号。(但可以借助在构造函数内抛出异常的方式发出错误信号)
  • 命名限制。限制了灵活性,例如两个构造函数不能同时具有一个整型参数。
  • 静态绑定创建。在构造对象时,必须指定编译时能够确定的特定类名。例如,Foo *f=new Foo(),Foo必须是编译器已知的具体类型。
  • 不允许虚构造函数。正如上一条,必须指定编译时要构造对象的精确类型。然后,编译器才能为特定类型分配内存并为任意基类调用默认构造函数。编译器随后为指定类型本身调用构造函数。(这一点就是为何不能在构造函数调用虚函数并期望它们调用派生类的overwrite的原因,因为派生类此时还没有被初始化)。

更为详细的说明参见面试语法糖(一)。(虚函数的作用在于通过基类的指针或者引用来调用它的时候能够变成调用派生类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。)

先入为主,工厂模式就是绕开这些限制,从基本层面来看,工厂方法就是一个普通的方法调用,该调用返回类的实例。但是,它们经常和继承一起使用,即派生类能够重写工厂方法并返回派生类的实例。常见的做法是使用抽象基类(Abstract Base Classes)也可以称为纯虚类。

 

对于图像API,流行的libjpeg库提供了JPEG/JFIF编解码器的实现,libpng库用于处理PNG格式的图像,大量的libtiff库模式用于读写各种风格的TIFF文件。问题来了,能不能采用一个普遍适用的接口来读取各种形式的图片呢?工厂模式的应用就必不可少了!!!

让我们来分析一下Opncv2.3.1的图像读写框架。主要分析cvSaveImage函数的实现,位于"OpenCV/otherlibs/highgui/loadsave.cpp"

CvImageFilters在构造的时候,将已知的图像读写驱动保存到一个链表中。内部实现的时候 可以看到很 有趣的现象,其使用了工厂函类 来实现

GrFmtFactoriesList在grfmt_base.h/grfmt_base.cpp中定义,用于保存GrFmtFilterFactory对象指针的链表

维护的时候构造函数只需通过工厂类来不断加入新功能支持新的图片格式

工厂类链表定义如下:

FindReader/FindWriter用于查找图像对应的驱动。如果想修改查找的规则,可以通过GetNextFactory遍历链表来实现。

真正的读写类从GrFmtReader派生,分别对应grfmt_bmp/grfmt_jpeg等各种格式驱动。然后通过前面的CvImageFilters::CvImageFilters()构造函数来将各个驱动串添加到g_Filters.m_factories链表中。

GrFmtFilterFactory为各种格式图像读写驱动的构造工厂基类

3个virtual函数,分表用于读图像文件头、读数据、关闭图像文件。图像文件在读图像头的时候被打开。

对于图像的其他属性,可以通过在子类中直接操作m_iscolor等protected成员完成。

定义了一个抽象基类,包含了纯虚方法。对于各种图像格式,定义了其派生类

 

所有的图片格式类 都是该基GrFmtFilterFactory的继承,如:GrFmtBmp 的继承,并通过NewReader生成真正处 理 图片的类: GrFmtBmpReader,传出的指针是它基类 :GrFmtReader

一些其他的方法实现,可以不用看。