Factory Methods



Similar documents

第2章 数据类型、常量与变量

<4D F736F F D C3E6CFF2B6D4CFF3A3A8B5DAC8FDD5C220C0E0CCD8D0D4A3A92E646F63>

龚 亚 夫 在 重 新 思 考 基 础 教 育 英 语 教 学 的 理 念 一 文 中 援 引 的 观 点 认 为 当 跳 出 本 族 语 主 义 的 思 维 定 式 后 需 要 重 新 思 考 许 多 相 连 带 的 问 题 比 如 许 多 发 音 的 细 微 区 别 并 不 影 响 理 解 和

修改版-操作手册.doc

<433A5C446F63756D656E E E67735C41646D696E F725CD7C0C3E65CC2DBCEC4CFB5CDB3CAB9D3C3D6B8C4CFA3A8BCF2BBAFA3A95CCAB9D3C3D6B8C4CF31302D31392E646F63>

《C语言基础入门》课程教学大纲

Microsoft PowerPoint - plan03.ppt

类 似 地, 又 可 定 义 变 下 限 的 定 积 分 : ( ). 与 ψ 统 称 为 变 限 积 分. f ( ) d f ( t) dt,, 注 在 变 限 积 分 (1) 与 () 中, 不 可 再 把 积 分 变 量 写 成 的 形 式 ( 例 如 ) 以 免 与 积 分 上 下 限 的

国债回购交易业务指引

Microsoft Word - 第7章 图表反转形态.doc

说 明 为 了 反 映 教 运 行 的 基 本 状 态, 为 校 和 院 制 定 相 关 政 策 和 进 行 教 建 设 与 改 革 提 供 据 依 据, 校 从 程 资 源 ( 开 类 别 开 量 规 模 ) 教 师 结 构 程 考 核 等 维 度, 对 2015 年 春 季 期 教 运 行 基

,,,,, :,, (.,, );, (, : ), (.., ;. &., ;.. &.., ;, ;, ),,,,,,, ( ) ( ),,,,.,,,,,, : ;, ;,.,,,,, (., : - ),,,, ( ),,,, (, : ),, :,

全国建筑市场注册执业人员不良行为记录认定标准(试行).doc

I

何 秋 琳 张 立 春 视 觉 学 习 研 究 进 展 视 觉 注 意 视 觉 感 知

用节点法和网孔法进行电路分析

Template BR_Rec_2005.dot

中 国 软 科 学 年 第 期!!!

评 委 : 李 炎 斌 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

徐天宏:《基因天堂》.doc

Microsoft Word - JAVA3.rtf

电信系教学大纲的基本规范

目 录 关 于 图 标... 3 登 陆 主 界 面... 3 工 单 管 理... 5 工 单 列 表... 5 搜 索 工 单... 5 工 单 详 情... 6 创 建 工 单... 9 设 备 管 理 巡 检 计 划 查 询 详 情 销 售 管

Microsoft Word - 文件汇编.doc

深圳市新亚电子制程股份有限公司

马 克 思 主 义 公 正 观 的 基 本 向 度 及 方 法 论 原 则!! # #

评 委 : 徐 岩 宇 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

第二讲 数列

抗 日 战 争 研 究 年 第 期


一 开 放 性 的 政 策 与 法 规 二 两 岸 共 同 的 文 化 传 承 三 两 岸 高 校 各 自 具 有 专 业 优 势 远 见 杂 志 年 月 日

随着执业中医师资格考试制度的不断完善,本着为我校中医学专业认证服务的目的,本文通过对我校中医类毕业生参加2012年和2013年的中医执业医师考试成绩及通过率、掌握率进行分析,并与全国的平均水平进行差异比较分析,以此了解我校执业中医师考试的现状,进而反映我校中医类课程总体教学水平,发现考核知识模块教学中存在的不足,反馈给相关学院和教学管理部门,以此提高教学和管理水平。

Microsoft PowerPoint - plan03.ppt

珠江钢琴股东大会


<4D F736F F D20B9D8D3DAB0BABBAAA3A8C9CFBAA3A3A9D7D4B6AFBBAFB9A4B3CCB9C9B7DDD3D0CFDEB9ABCBBE C4EAC4EAB6C8B9C9B6ABB4F3BBE1B7A8C2C9D2E2BCFBCAE92E646F6378>


模 型 假 设 假 设 假 设 假 设 假 设 假 设 模 型 建 立 与 推 导

导 数 和 微 分 的 概 念 导 数 的 几 何 意 义 和 物 理 意 义 函 数 的 可 导 性 与 连 续 性 之 间 的 关 系 平 面 曲 线 的 切 线 和 法 线 导 数 和 微 分 的 四 则 运 算 基 本 初 等 函 数 的 导 数 复 合 函 数 反 函 数 隐 函 数 以

国际财务报告准则第13号——公允价值计量

( 二 ) 现 行 统 一 高 考 制 度 不 利 于 培 养 人 的 创 新 精 神,,,,,,,,,,,,, [ ],,,,,,,,,,, :, ;,,,,,,? ( 三 ) 现 行 统 一 高 考 制 度 不 利 于 全 体 学 生 都 获 得 全 面 发 展,, [ ],,,,,,,,,,,


0 年 上 半 年 评 价 与 考 核 细 则 序 号 部 门 要 素 值 考 核 内 容 考 核 方 式 考 核 标 准 考 核 ( 扣 原 因 ) 考 评 得 3 安 全 生 产 目 30 无 同 等 责 任 以 上 道 路 交 通 亡 人 事 故 无 轻 伤 责 任 事 故 无 重 大 质 量

登录、注册功能的测试用例设计.doc

¹ º ¹ º 农 业 流 动 人 口 是 指 户 口 性 质 为 农 业 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个 月 及 以 上 的 流 动 人 口 非 农 流 动 人 口 是 指 户 口 性 质 为 非 农 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个

 编号:

抗 战 时 期 国 民 政 府 的 银 行 监 理 体 制 探 析 % # % % % ) % % # # + #, ) +, % % % % % % % %

上证指数

年 第 期 % %! & % % % % % % &

金 不 少 于 800 万 元, 净 资 产 不 少 于 960 万 元 ; (3) 近 五 年 独 立 承 担 过 单 项 合 同 额 不 少 于 1000 万 元 的 智 能 化 工 程 ( 设 计 或 施 工 或 设 计 施 工 一 体 ) 不 少 于 2 项 ; (4) 近 三 年 每 年

生产支援功能 使用说明书(IP-110 篇)

<4D F736F F D C4EAB9A4B3CCCBB6CABFCAFDD1A7D7A8D2B5BFCEBFBCCAD4B4F3B8D9D3EBD2AAC7F3>

定 位 和 描 述 : 程 序 设 计 / 办 公 软 件 高 级 应 用 级 考 核 内 容 包 括 计 算 机 语 言 与 基 础 程 序 设 计 能 力, 要 求 参 试 者 掌 握 一 门 计 算 机 语 言, 可 选 类 别 有 高 级 语 言 程 序 设 计 类 数 据 库 编 程 类

自 在 期 年 以 前 这 一 时 期 舞 龙 的 概 况 銃 一 对 唢 呐 等

<4D F736F F D20B2CEBFBC3232C6DAD1A7CFB0D3EBCBBCBFBCC4DAD2B3>

<4D F736F F D20BFC9B1E0B3CCD0F2BFD8D6C6CFB5CDB3C9E8BCC6CAA6B9FABCD2D6B0D2B5B1EAD7BC2E646F63>

正 规 培 训 达 规 定 标 准 学 时 数, 并 取 得 结 业 证 书 二 级 可 编 程 师 ( 具 备 以 下 条 件 之 一 者 ) (1) 连 续 从 事 本 职 业 工 作 13 年 以 上 (2) 取 得 本 职 业 三 级 职 业 资 格 证 书 后, 连 续 从 事 本 职 业

第 三 章 审 计 证 据 2

untitled


·岗位设置管理流程

第三章 作业

( ) 信 号 与 系 统 Ⅰ 学 科 基 础 必 修 课 教 周 2016 年 06 月 13 日 (08:00-09:35) ( )

(Microsoft Word - NCRE\314\345\317\265\265\367\325\37313\324\27221\272\3051.doc)

!!!!!

鄂考院﹝2016﹞2号

一 公 共 卫 生 硕 士 专 业 学 位 论 文 的 概 述 学 位 论 文 是 对 研 究 生 进 行 科 学 研 究 或 承 担 专 门 技 术 工 作 的 全 面 训 练, 是 培 养 研 究 生 创 新 能 力, 综 合 运 用 所 学 知 识 发 现 问 题, 分 析 问 题 和 解 决

3 月 30 日 在 中 国 证 券 报 上 海 证 券 报 证 券 时 报 证 券 日 报 和 上 海 证 券 交 易 所 网 站 上 发 出 召 开 本 次 股 东 大 会 公 告, 该 公 告 中 载 明 了 召 开 股 东 大 会 的 日 期 网 络 投 票 的 方 式 时 间 以 及 审

第 期 李 伟 等 用 方 法 对 中 国 历 史 气 温 数 据 插 值 可 行 性 讨 论

采 取 行 动 的 机 会 90% 开 拓 成 功 的 道 路 2

操作手册

( 此 页 无 正 文, 为 广 东 东 方 精 工 科 技 股 份 有 限 公 司 关 于 提 供 资 料 真 实 准 确 和 完 整 的 承 诺 函 之 签 署 页 ) 广 东 东 方 精 工 科 技 股 份 有 限 公 司 法 定 代 表 人 : 唐 灼 林 2016 年 7 月 28 日


教师上报成绩流程图

附件1:


2. 本 次 修 改 后, 投 资 者 申 购 新 股 的 持 有 市 值 要 求 市 值 计 算 规 则 及 证 券 账 户 使 用 的 相 关 规 定 是 否 发 生 了 变 化? 答 : 未 发 生 变 化 投 资 者 申 购 新 股 的 持 有 市 值 是 指, 以 投 资 者 为 单 位

<443A5C6D B5C30312EB9A4D7F7CEC4B5B55C30322EBACFCDACCEC4B5B55C C30342EC8CBC9E7CCFC5C31332ECFEEC4BFC5E0D1B55C E30385C322EB2D9D7F7CAD6B2E12E646F63>

变 量 的 主 要 作 用 是 存 取 数 据 提 供 存 放 信 息 的 容 器 对 于 变 量 必 须 明 确 变 量 的 命 名 变 量 的 类 型 变 量 的 声 明 及 其 变 量 的 作 用 域 JavaScript 是 一 种 弱 类 型 语 言, 也 就 是 说, 在 声 明 变 量

在2012年工作会议结束时的讲话

微 积 分 ( 二 ) 教 学 大 纲 2 (2010 版 ) 课 程 编 码 : 课 程 名 称 : 微 积 分 学 时 / 学 分 :36/2 先 修 课 程 : 初 等 数 学 立 体 几 何 平 面 解 析 几 何 微 积 分 ( 一 ) 适 用 专 业 : 人 力 资 源 管

新, 各 地 各 部 门 ( 单 位 ) 各 文 化 事 业 单 位 要 高 度 重 视, 切 实 加 强 领 导, 精 心 组 织 实 施 要 根 据 事 业 单 位 岗 位 设 置 管 理 的 规 定 和 要 求, 在 深 入 调 查 研 究 广 泛 听 取 意 见 的 基 础 上, 研 究 提


<4D F736F F D20B9D8D3DA BDECB1CFD2B5C9FAC5C9C7B2B1A8B5BDB5C8D3D0B9D8B9A4D7F7B5C4CDA8D6AAA3A E362E38A3A92E646F63>

第 一 部 分 MagiCAD for Revit 安 装 流 程

一 六 年 级 下 册 教 科 书 总 体 说 明 ( 一 ) 教 学 内 容 本 册 教 科 书 一 共 安 排 了 5 个 教 学 单 元, 其 中 前 4 个 单 元 为 新 知 识, 第 五 单 元 是 对 整 个 小 学 阶 段 所 学 数 学 知 识 系 统 的 整 理 和 复 习

境 外 上 市 外 资 股 股 东 持 有 股 份 总 数 (H 股 ) 489,157,907 3 出 席 会 议 的 股 东 所 持 有 表 决 权 股 份 数 占 公 司 有 表 决 权 股 份 总 数 的 其 中 :A 股 股 东 持 股 占 股 份 总 数 的

doc

国 际 中 国 研 究 动 态 是 中 国 社 会 科 学 院 国 际 中 国 学 研 究 中 心 出 品 的 以 介 绍 国 际 中 国 问 题 研 究 最 新 成 果 为 宗 旨 的 电 子 杂 志 计 划 每 月 出 版 一 期 除 编 译 和 摘 编 网 络 和 中 外 期 刊 库 上 可

注 意 : 如 上 图 所 示, 网 上 缴 费 (12 月 3 日 至 10 日 ) 与 春 季 高 考 现 场 确 认 工 作 (12 月 3 日 至 6 日 ) 同 时 进 行, 没 有 经 过 现 场 确 认 和 确 认 信 息 没 有 上 传 到 服 务 器 的 考 生 不 能 网 上 缴

课程类 别

长 安 侠 少 每 至 春 时 结 朋 联 党 各 置 矮 马 饰 以 锦 鞯 金 铃 并 辔 于 花 树 下 往 来 使 仆 人 执 酒 皿 而 随 之 遇 好 酒 则 驻 马 而 饮

一、资质申请

ETF、分级基金规模、份额变化统计

<4D F736F F D20B3D6B2D6CFDEB6EEB1EDB8F1D7EED6D52E646F63>

上海证券交易所会议纪要

黄 金 原 油 总 持 仓 增 长, 同 比 增 幅 分 别 为 4.2% 和 4.1% 而 铜 白 银 以 及 玉 米 则 出 现 减 持, 减 持 同 比 减 少 分 别 为 9.4%,9.4% 以 及 6.5% 大 豆, 豆 粕 结 束 连 续 4 周 总 持 仓 量 增 长, 出 现 小 幅

# 抗 日 战 争 研 究 年 第 期, 胊 县 多, # # # # # # # # # # # # # # # # # # # # #

西 南 民 族 学 院 学 报 哲 学 社 会 科 学 版 第 卷 资 料 来 源 中 国 统 计 年 鉴 年 年 新 中 国 五 十 年 统 计 资 料 汇 编 中 国 人 口 统 计 年 鉴 年 数 据 资 料 来 源 中 国 统 计 年 鉴 中 国 统 计 出 版 社 年 版 资 料 来 源

Transcription:

Factory Methods 工 厂 方 法 eryar@163.com 摘 要 Abstract: 本 文 主 要 是 对 API Design for C++ 中 Factory Methods 章 节 的 翻 译, 若 有 不 当 之 处, 欢 迎 指 正 关 键 字 Key Words:C++ Factory Pattern 一 概 述 Overview 工 厂 方 法 是 创 建 型 模 式, 允 许 在 不 指 定 需 要 创 建 对 象 类 型 的 情 况 下 创 建 出 对 象 本 质 上 来 说, 工 厂 方 法 就 是 一 个 通 用 的 构 造 函 数 C++ 中 的 构 造 函 数 有 以 下 几 种 限 制 : 无 返 回 值 (No return result) 在 构 造 函 数 中 不 能 返 回 一 个 值 这 就 意 味 着 : 例 如 当 构 造 失 败 时 不 能 返 回 一 个 NULL 作 为 初 始 化 失 败 的 信 号 命 名 有 约 束 (Constrained naming) 构 造 函 数 还 是 很 好 识 别 的, 因 为 它 的 命 名 必 须 与 类 名 一 样 静 态 绑 定 创 建 的 (Statically bound creation) 当 创 建 一 个 对 象 时, 必 须 指 定 一 个 在 编 译 时 就 能 确 定 的 类 名 如 :Foo *f = new Foo(),Foo 就 是 编 译 器 必 须 知 道 的 类 名 C++ 的 构 造 函 数 没 有 运 行 时 的 动 态 绑 定 功 能 (dynamic binding at run time) 无 虚 构 造 函 数 (No virtual constructors) 在 C++ 中 不 能 声 明 虚 的 构 造 函 数, 必 须 指 定 在 编 译 时 能 确 定 的 类 型 编 译 器 据 此 为 指 定 的 类 型 分 配 内 存, 然 后 调 用 基 类 的 默 认 构 造 函 数, 再 调 用 指 定 类 的 构 造 函 数 这 就 是 不 能 定 义 构 造 函 数 为 虚 函 数 的 原 因 相 反 地, 工 厂 方 法 (factory methods) 突 破 了 以 上 所 有 的 限 制 工 厂 方 法 的 基 本 功 能 就 是 一 个 可 以 返 回 一 个 类 的 实 例 的 简 单 函 数 但 是, 它 通 常 与 继 承 组 合 使 用, 派 生 的 类 可 以 重 载 工 厂 方 法 以 返 回 派 生 类 的 实 例 使 用 抽 象 基 类 (Abstract Base Classes) 来 实 现 工 厂 很 常 见, 也 很 有 用 二 抽 象 基 类 Abstract Base Classes 抽 象 基 类 就 是 包 含 一 个 或 多 个 纯 虚 函 数 (pure virtual methods) 的 类, 这 样 的 类 不 是 具 体 类 且 不 能 用 new 来 实 例 化 相 反 地, 它 是 作 为 其 它 派 生 类 的 基 类, 由 派 生 类 来 具 体 实 现 那 些 纯 虚 函 数 例 如 : #ifndef RENDERER_H #define RENDERER_H #include <string> An abstract interface for a 3D renderer. class IRenderer

virtual ~IRenderer() virtual bool LoadScene(const std:: ::string &filename) = 0; virtual void SetViewportSize(int w, int h) = 0; virtual void SetCameraPos(double x, double y, double z) = 0; virtual void SetLookAt(double x, double y, double z) = 0; virtual void Render() = 0; #endif 上 述 代 码 定 义 了 一 个 抽 象 基 类, 描 述 了 一 个 相 当 简 单 的 3D 图 形 渲 染 器 (renderer) 函 数 的 后 缀 =0 声 明 这 个 函 数 是 纯 虚 函 数, 表 示 这 个 函 数 必 须 由 其 派 生 类 来 具 体 实 现 抽 象 基 类 是 描 述 了 多 个 类 共 有 的 行 为 的 抽 象 单 元, 它 约 定 了 所 有 具 体 派 生 类 必 须 遵 守 的 合 同 在 Java 中, 抽 象 基 类 也 叫 接 口 (interface), 只 是 Java 的 接 口 只 能 是 公 用 的 方 法 (public method), 静 态 变 量, 并 且 不 能 定 义 构 造 函 数 将 类 名 IRenderer 带 上 I 就 是 为 了 表 明 这 个 类 是 接 口 类 (interface class) 当 然, 抽 象 基 类 中 并 不 是 所 有 的 方 法 都 必 须 是 纯 虚 函 数, 也 可 以 实 现 一 些 函 数 当 任 意 一 个 类 有 一 个 或 多 个 虚 函 数 时, 通 常 会 把 抽 象 基 类 的 析 构 函 数 声 明 为 虚 函 数 如 下 代 码 说 明 了 这 样 做 的 重 要 性 : class IRenderer // no virtual destructor declared virtual void Render() = 0; class RayTracer : public IRenderer RayTracer(); ~RayTracer(); void Render(); // provide implementation for ABC method int main(int, char **) IRenderer *r = new RayTracer(); // delete calls IRenderer::~IRenderer, not RayTracer::~RayTracer delete r; 三 简 单 工 厂 模 式 Simple Factory Example 在 复 习 了 抽 象 基 类 后, 让 我 们 在 简 单 工 厂 方 法 中 使 用 它 继 续 以 renderer.h 为 例, 声 明 创 建 工 厂, 创 建 的 对 象 类 型 为 IRenderer, 代 码 如 下 所 示 : #ifndef RENDERERFACTORY_H

#define RENDERERFACTORY_H #include "renderer.h" #include <string> A factory object that creates instances of different 3D renderers. class RendererFactory Create a new instance of a named 3D renderer. type can be one of "opengl", "directx", or "mesa" IRenderer *CreateRenderer(const std:: ::string &type); #endif 这 里 只 声 明 了 一 个 工 厂 方 法 : 它 只 是 一 个 普 通 的 函 数, 返 回 值 是 对 象 的 实 例 注 意 到 这 个 方 法 不 能 返 回 一 个 指 定 类 型 的 IRender 实 例, 因 为 抽 象 基 类 是 不 能 被 实 例 化 的 但 是 它 可 以 返 回 派 生 类 的 实 例 当 然, 你 可 以 使 用 字 符 串 作 为 参 数 来 指 定 需 要 创 建 对 象 的 类 型 假 设 已 经 实 现 了 派 生 自 IRender 的 三 个 具 体 类 : IRenderer::OpenGLRenderer, DirectXRenderer MesaRenderer 再 假 设 你 不 想 让 使 用 API 的 用 户 知 道 可 以 创 建 哪 些 类 型 : 他 们 必 须 完 全 隐 藏 在 API 后 面 基 于 这 些 条 件, 可 以 实 现 工 厂 方 法 的 程 序 如 下 : // 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 的 三 个 派 生 类 之 一 的 实 例, 取 决 于 传 入 的 参 数 字 符 串

这 就 可 以 让 用 户 决 定 在 运 行 时 而 不 是 在 编 译 时 创 建 哪 个 派 生 类, 这 与 普 通 的 构 造 函 数 要 求 一 致 这 样 做 是 有 很 多 好 处 的, 因 为 它 可 以 根 据 用 户 输 入 或 根 据 运 行 时 读 入 的 配 置 文 件 内 容 来 创 建 不 同 的 对 象 另 外, 注 意 到 实 现 具 体 派 生 类 的 头 文 件 只 在 rendererfactory.cpp cpp 中 被 包 含 它 们 不 出 现 在 rendererfactory.h 这 个 公 开 的 头 文 件 中 实 际 上, 这 些 头 文 件 是 私 有 的 头 文 件, 且 不 需 要 与 API 一 起 发 布 的 这 样 用 户 就 看 不 到 不 同 的 渲 染 器 的 私 有 细 节, 也 看 不 到 具 体 可 以 创 建 哪 些 不 同 的 渲 染 器 用 户 只 需 要 通 过 字 符 串 变 量 来 指 定 种 要 创 建 的 渲 染 器 ( 若 你 愿 意, 也 可 用 一 个 枚 举 来 区 分 类 型 ) 此 例 演 示 了 一 个 完 全 可 接 受 的 工 厂 方 法 但 是, 其 潜 在 的 缺 点 就 是 包 含 了 对 可 用 的 各 派 生 类 的 硬 编 码 若 系 统 需 要 添 加 一 个 新 的 渲 染 器, 你 必 须 再 编 辑 rendererfactory.cpp 这 并 不 会 让 人 很 烦, 重 要 的 是 不 会 影 响 你 提 供 的 公 用 的 API 但 是, 他 的 确 不 能 在 运 行 时 添 加 支 持 的 新 的 派 生 类 再 专 业 点, 这 意 味 着 你 的 用 户 不 能 向 系 统 中 添 加 新 的 渲 染 器 通 过 扩 展 的 对 象 工 厂 来 解 决 这 些 问 题 四 扩 展 工 厂 模 式 Extensible Factory Example 为 了 让 工 派 生 类 从 工 厂 方 法 中 解 耦, 且 允 许 在 运 行 时 添 加 新 的 派 生 类, 可 以 去 维 护 包 含 类 型 及 与 类 型 创 建 关 联 的 函 数 的 映 射 (map) 来 更 新 一 下 工 厂 类 可 以 通 过 添 加 几 个 新 的 函 数 用 来 注 册 与 注 销 新 的 派 生 类 在 运 行 时 能 注 册 新 的 类 允 许 这 种 类 型 的 工 厂 方 法 模 式 可 用 于 创 建 可 扩 展 的 接 口 还 有 个 需 要 注 意 的 事 是 工 厂 对 象 必 须 保 存 状 态, 即 最 好 只 有 一 个 工 厂 对 象 这 也 是 工 厂 对 象 通 常 是 单 件 的 (singletons) 为 了 程 序 的 简 单 明 了, 这 里 使 用 静 态 变 量 为 例 将 所 有 要 点 都 考 虑 进 来, 新 的 工 厂 对 象 代 码 如 下 所 示 : #ifndef RENDERERFACTORY_H #define RENDERERFACTORY_H #include "renderer.h" #include <string> #include <map> A factory object that creates instances of different 3D renderers. New renderers can be dynamically added and removed from the factory object. class RendererFactory The type for the callback that creates an IRenderer instance typedef IRenderer *(*CreateCallback)(); Add a new 3D renderer to the system static void RegisterRenderer(const std::string &type, CreateCallback cb); Remove an existing 3D renderer from the system static void UnregisterRenderer(const std::string &type);

Create an instance of a named 3D renderer static IRenderer *CreateRenderer(const std::string &type); private: typedef std::map<std::string, CreateCallback> CallbackMap; static CallbackMap mrenderers; #endif 为 了 程 序 的 完 整 性, 将 其.cpp 文 件 中 的 代 码 示 例 如 下 : #include "rendererfactory.h" #include <iostream> // instantiate the static variable in 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()) // call the creation callback to construct this derived type return (it->second)(); return NULL; 使 用 工 厂 对 象 创 建 派 生 类 的 方 法 如 下 所 示 : #include "rendererfactory.h" #include <iostream> using std::cout;

using std::endl; An OpenGL-based 3D renderer class OpenGLRenderer : public IRenderer ~OpenGLRenderer() bool LoadScene(const std::string &filename) return true; void SetViewportSize(int w, int h) void SetCameraPos(double x, double y, double z) void SetLookAt(double x, double y, double z) void Render() cout << "OpenGL Render" << endl; static IRenderer *Create() return new OpenGLRenderer; A DirectX-based 3D renderer class DirectXRenderer : public IRenderer bool LoadScene(const std::string &filename) return true; void SetViewportSize(int w, int h) void SetCameraPos(double x, double y, double z) void SetLookAt(double x, double y, double z) void Render() cout << "DirectX Render" << endl; static IRenderer *Create() return new DirectXRenderer; A Mesa-based software 3D renderer class MesaRenderer : public IRenderer bool LoadScene(const std::string &filename) return true; void SetViewportSize(int w, int h) void SetCameraPos(double x, double y, double z) void SetLookAt(double x, double y, double z) void Render() cout << "Mesa Render" << endl; static IRenderer *Create() return new MesaRenderer; int main(int, char **) // register the various 3D renderers with the factory object RendererFactory::RegisterRenderer("opengl", OpenGLRenderer::Create);

RendererFactory::RegisterRenderer("directx", DirectXRenderer::Create); RendererFactory::RegisterRenderer("mesa", MesaRenderer::Create); // create an OpenGL renderer IRenderer *ogl = RendererFactory::CreateRenderer("opengl"); ogl->render(); delete ogl; // create a Mesa software renderer IRenderer *mesa = RendererFactory::CreateRenderer("mesa"); mesa->render(); delete mesa; // unregister the Mesa renderer RendererFactory::UnregisterRenderer("mesa"); mesa = RendererFactory::CreateRenderer("mesa"); if (! mesa) cout << "Mesa renderer unregistered" << endl; return 0; 你 的 API 的 用 户 可 以 在 系 统 中 注 册 与 注 销 一 个 新 的 渲 染 器 编 译 器 将 会 确 保 用 户 定 义 的 新 的 渲 染 器 必 须 实 现 抽 象 基 类 IRenderer 的 所 有 抽 象 接 口, 即 新 的 渲 染 器 类 必 须 实 现 抽 象 基 类 IRenderer 所 有 的 纯 虚 函 数 如 下 代 码 演 示 了 用 户 如 何 自 定 义 新 的 渲 染 器, 在 工 厂 对 象 中 注 册, 并 叫 工 厂 对 象 为 之 创 建 一 个 实 例 : 这 里 需 要 注 意 的 一 点 是 我 向 类 UserRenderer 中 添 加 了 一 个 Create() 函 数, 这 是 因 为 工 厂 对 象 的 注 册 方 法 需 要 返 回 一 个 对 象 的 回 调 函 数 这 个 回 调 函 数 不 一 定 必 须 是 抽 象 基 类 IRenderer 的 一 部 分, 它 可 以 是 一 个 自 由 的 函 数 但 是 向 抽 象 基 类 IRenderer 中 添 加 这 个 函 数 是 一 个 好 习 惯, 这 样 就 确 保 了 所 有 相 关 功 能 的 一 致 性 实 际 上, 为 了 强 调 这 种 约 定, 可 以 将 Create 作 为 抽 象 基 类 IRenderer 的 一 个 纯 虚 函 数 五 结 论 Conclusion Finally, I note that in the extensible factory example given here, a renderer callback has to be visible to the RegisterRenderer() function at run time. However, this doesn t mean that you have to expose the built-in in renderers of your API. These can still be hidden either by registering them within your API initialization routine or by using a hybrid of the simple factory and the extensible factory, whereby the factory method first checks the type string against a few built-in in names. If none of those match, it then checks for any names that have been registered by the user. This hybrid approach has the potentially desirable behavior that users cannot override your built-in in classes.