一、抽象基类

抽象基类是包含一个或多个纯虚成员函数的类。它不是实体类,不能使用new操作符进行实例化,而只能用作一个基类,并由派生类提供纯虚方法的实现。e.g.

//renderer.h
class IRenderer
{
public:virtual ~IRenderer() {}virtual void Render() = 0;virtual void SetViewportSize(const std::string& filename) = 0;
};

严格讲,“纯虚方法不提供实现”的说法是不正确的。实际上,可以再.cpp文件中为纯虚方法提供默认实现。例如,可以再render.cpp中为SetViewportSize()提供一个实现,然后派生类就可以调用IRenderer::SetViewportSize(),但它仍需要显示地重写此方法。

抽象基类可用于描述多个类共享的行为的抽象单元,它指定了所有派生类都必须遵循的契约。在Java中,它被称为接口(Java接口只能包含公有方法、静态变量且不能定义构造函数)。将上述的类命名为IRender,以I作为前缀,以此表明它是一个接口类。

二、工厂示例

//rendererfactory.h
#include "renderer.h"
#include <string>
class RendererFactory
{
public:IRenderer* CreateRenderer(const std::string& type);
};
//rendererfactory.cpp
#include "rendererfactory.h"
#include "openglrenderer.h"
#include "directxrenderer.h"
#include "mesarenderer.h"IRenderer* RendererFactory::CreateRenderer(const std::string& type)
{if (type == "opengl")return new OpenGLRenderer();if (type == "directx")return new DirectXRenderer();if (type == "mesa")return new MesaRenderer();return NULL;
}

此工厂方法能够返回IRenderer的3个派生类中的任意一个,返回那个派生类则取决于客户传递的类型字符串。这就允许用户在运行时决定要创建哪个派生类,而不是在编译时要求用户使用正常的构造函数创建类。这是一个巨大的优势,因为它意味着能够基于用户输入或根据运行时读入的配置文件创造不同的类。

另外,还要注意各个具体的派生类的头文件仅包含在工厂的.cpp文件中。它们不会出现在公有头文件rendererfactory.h中。实际上,这些都是私有头文件,且不需要和API一起发布。因此,用户永远看不到不同渲染器的私有细节,他们甚至看不到实现不同渲染器的具体类型。用户只能通过字符串变量指定渲染器(也可以使用枚举类型)。

这是一个完全可行的工厂方法。但它的一个潜在缺陷是,包含了可用的派生类的硬编码信息。如果要为系统添加新的渲染器,则必须修改rendererfactory.cpp。这个改动不是非常繁重,而且最重要的是它不会影响公有的API。但这也意味着不能为新的派生类添加运行时支持。换句话说,用户不能为系统添加新的渲染器。这些问题可以使用可扩展的对象工厂来解决。

三、扩展工厂示例

//rendererfactory.h
#include "renderer.h"
#include <string>
#include <map>class RendererFactory
{
public:typedef IRenderer* (*CreateCallback)();static void RegisterRenderer(const std::string& type, CreateCallback cb);static void UnregisterRenderer(const std::string& type);static IRenderer* CreateRenderer(const std::string& type);private:typedef std::map<std::string, CreateCallback> CallbackMap;static CallbackMap mRenderers;
};
//rendererfactory.cpp
#include "rendererfactory.h"//在RendererFactory中实例化静态变量
RendererFactory::CallbackMap RendererFactory::mRenderers;void RendererFactory::RegisterRenderer(const std::string& type, CreateCallback cb)
{mRenderers[type] = cb;
}void RendererFactory::UnregisterRenderer(const std::string& type)
{mRenderers.erase(type);
}IRenderer* RendererFactory::CreateRenderer(const std::string& type)
{CallbackMap::iterator it = mRenderers.find(type);if (it != mRenderers.end()){//调用回调以构造此派生类型的对象return (it->second)();}return NULL;
}
//main.cpp
#include "rendererfactory.h"class UserRenderer : public IRenderer
{
public:~UserRenderer() {}void SetViewportSize(int w, int h) {}void Render() { std::cout << "User Render" << std::endl; }static IRenderer* Create() { return new UserRenderer(); }
};int main()
{//注册一个新的渲染器RendererFactory::RegisterRenderer("user", UserRenderer::Create);//为新渲染器创建一个实例IRenderer* r = RendererFactory::CreateRenderer("user");r->Render();delete r;return 0;
}

工厂类维护一个映射,此映射将类型名与创建对象的回调关联起来。然后就可以允许新的派生类通过一对新的方法调用来实现注册和注销。

需要注意的另一个问题是,工厂对象必须保存其状态信息。因此,最好强制要求任一时刻都只能创建一个工厂对象。这也是为何多数工厂对象也是单例的原因。

参考资料:

《C++ API设计》

[设计模式] - 工厂模式相关推荐

  1. Java设计模式-工厂模式(3)抽象工厂模式

    在Java设计模式-工厂模式(2)工厂方法模式 我们知道了工厂方法模式解决了简单工厂模式中的缺陷,做到了满足开闭原则,但是时代是进步的,进而又产生新的问题,工厂难道只能生产一种东西吗.我们所见到的工厂 ...

  2. Java设计模式-工厂模式(2)工厂方法模式

    在Java设计模式-工厂模式(1)简单工厂模式 中我们介绍了简单工厂模式,提到了简单工厂模式违背了开闭原则,而"工厂方法模式"是对简单工厂模式的进一步抽象化,其好处是可以使系统在不 ...

  3. Java设计模式-工厂模式(1)简单工厂模式

    Java设计模式-工厂模式(1)简单工厂模式 一.前言 1)例子 2)类图关系 3)代码实现 二.简单工厂模式 2.1.概述: 2.2.类图关系: 2.3.代码修改: 2.4.优缺点 2.5.扩展-简 ...

  4. 设计模式---工厂模式

    设计模式---工厂模式 工厂方法模式 概述:工厂方法模式中抽象工厂负责定义创建对象的接口,具体创建工作由继承抽象工厂的具体类实现. 优点:客户端不需要再负责对象的创建,从而明确了各个类的职责,如果有新 ...

  5. java设计模式工厂模式_Java中的工厂设计模式

    java设计模式工厂模式 Welcome to the Factory Design Pattern in Java tutorial. Factory Pattern is one of the C ...

  6. java设计模式工厂模式_Java中的复合设计模式

    java设计模式工厂模式 Composite pattern is one of the Structural design pattern. Composite design pattern is ...

  7. java设计模式工厂模式_Java中的桥梁设计模式

    java设计模式工厂模式 Today we will look into Bridge Design Pattern in java. When we have interface hierarchi ...

  8. java设计模式工厂模式_Java中的外观设计模式

    java设计模式工厂模式 Facade Design Pattern is one of the Structural design patterns (such as Adapter pattern ...

  9. 设计模式-工厂模式(学习)

    设计模式-工厂模式(学习) 在程序的世界里,就像射雕英雄传一样,我们的技能就像是武功一样,我们只有不断去学习练习才能有机会像郭靖一样成为"天下第一". 我认为技能和武功是很类似的, ...

  10. 设计模式-工厂模式的3中不同实现[JAVA]

    设计模式-工厂模式的3中不同实现[JAVA] 工厂模式简介 In Factory pattern, we create object without exposing the creation log ...

最新文章

  1. 转:Ubuntu中安装和配置 Java JDK,并卸载自带OpenJDK(以Ubuntu 14.04为例)
  2. 网狐动态数组CWHArray
  3. E - Code Parsing CodeForces - 255B(思维)
  4. windows下hadoop的单机伪分布式部署(3)
  5. SQL语言的事务机制_转摘
  6. Win7 U盘安装Ubuntu16.04 双系统
  7. STM32——串口通信
  8. php ajax传值中文乱码问题,PHP Ajax JSON中文乱码各种问题解决办法
  9. BFC(块级化上下文)
  10. inner join 与 left join 之间的区别
  11. docker 训练深度学习_基于 Alluxio 数据缓存的大规模深度学习训练性能优化
  12. Sonix SN9P701 OCR点读笔二维码识别源码
  13. 全球区块链专利排行榜中国52家企业上榜
  14. mybatisplus的逻辑删除
  15. animation动画不生效_css animation不动怎么办
  16. I2C协议研读(九):十位寻址
  17. 敏捷开发与Scrum区别(敏捷开发(Agile)教程)
  18. 7-1 统计正数和负数的个数然后计算这些数的平均值 (15 分)-java
  19. Nginx中last和break redirect和permanent区别和联系
  20. windows 多种 socket 模型的理解

热门文章

  1. linux 添加接口永久,在Linux中,配置虚拟网络接口
  2. python 自动收集经济数据_完结】数据分析思维案例实战92 用Python自动办公,做职场高手【更新中】91.一课经济...
  3. Intellij IDEA 安装jnetpcap开发环境与 no jnetpcap in java.library.path 的解决方案
  4. Linux --- awk
  5. thinkphp5.0自定义验证器
  6. 每天一道Java题[4]
  7. 参数数组(params)的用法
  8. Chocolatey 简介(软件自动化管理工具)
  9. [刷题]算法竞赛入门经典(第2版) 6-7/UVa804 - Petri Net Simulation
  10. 软件的极简主义的三个大敌:配置文件,冗余的参数,和大量复杂的接口。