如 何 使 用 Delphi 开 发 大 型 主 从 架 构 系 统 - Package 的 秘 密 和 威 力(转自www.broland.com.tw)(0

  • 主题发起人 主题发起人 yangdear
  • 开始时间 开始时间
Y

yangdear

Unregistered / Unconfirmed
GUEST, unregistred user!
如 何 使 用 Delphi 开 发 大 型 主 从 架 构 系 统 - Package 的 秘 密 和 威 力(转自www.broland.com.tw)(0分)<br />如 何 使 用 Delphi 开 发 大 型 主 从 架 构 系 统 - Package 的 秘 密 和 威 力
相信许多人和我一样,在使用Delphi 开 发 应 用 系 统 的 时 候 , 一 定 会 想 到 如 何 的 切 割 整 个 应 用 系 统 。 是 把 所 有 的 子 系 统 撰 写 成 一 个 很 大 ( 可 能 会 有 数 M .Bytes 的 大 小 ) 的 EXE 檔 呢 ? 还 是 应 该 把 每 一 个 模 组 撰 写 在 不 同 的 EXE 檔 案 之 中 的 好 。
事 实 上 这 两 种 方 法 都 有 它 们 自 己 的 问 题 。 如 果 是 把 所 有 的 模 组 撰 写 在 一 个 EXE 檔 案 之 中 的 话 , 那 么 不 但 执 行 檔 太 大 , 不 易 更 新 和 维 护 。 在 开 发 时 也 不 甚 方 便 , 因 为 要 让 数 个 人 撰 写 同 一 支 应 用 程 式 的 确 比 较 麻 烦 。 那 么 如 果 我 们 把 每 一 个 模 组 让 不 同 的 程 式 师 撰 写 成 独 立 的 EXE 檔 案 , 再 由 一 个 主 程 式 分 别 启 动 不 同 的 EXE 檔 不 就 好 了 吗 ? 没 错 这 是 许 多 人 使 用 的 方 法 ( 包 括 我 在 内 ) , 但 是 这 样 切 割 应 用 系 统 有 一 个 问 题 , 那 就 是 如 果 每 一 个 独 立 的 EXE 模 组 , 都 需 要 使 用 资 料 库 的 话 , 那 么 当 主 程 式 启 动 个 别 的 EXE 檔 案 时 , 每 一 个 EXE 都 必 须 重 新 再 连 结 到 资 料 库 , 开 启 资 料 库 表 格 , 再 取 得 它 需 要 的 资 料 。 这 个 过 程 通 常 都 需 要 不 少 的 时 间 。 例 如 连 结 到 Oracle 并 且 开 启 一 个 资 料 库 表 格 的 话 , 通 常 需 要 五 到 十 秒 。 如 果 EXE 开 启 的 资 料 库 表 格 或 是 查 询 比 较 多 的 话 , 那 么 主 程 式 在 启 动 独 立 的 EXE 檔 案 时 , 通 常 需 要 3 0 几 秒 到 一 分 钟 不 等 。 这 对 于 许 多 的 使 用 者 而 言 是 非 常 不 方 便 的 。 这 样 的 状 状 甚 至 会 造 成 你 的 专 案 无 法 交 货 ( 例 如 使 用 者 要 求 在 五 秒 之 内 EXE 程 式 的 画 面 必 须 出 现 ) 。 除 此 之 外 , 每 一 个 独 立 的 EXE 又 使 用 了 额 外 的 连 结 以 便 存 取 资 料 库 , 造 成 了 资 源 的 浪 费 。 面 对 这 种 二 难 的 局 面 , 你 现 在 的 选 择 是 什 么 呢 ?
事 实 上 这 个 问 题 在 我 的 心 中 也 盘 旋 了 许 久 。 因 为 这 一 是 我 想 要 解 决 的 问 题 , 只 是 由 于 工 作 的 繁 忙 让 我 一 直 无 法 花 时 间 解 决 它 。 最 近 在 手 上 的 事 情 告 一 段 落 之 后 , 又 接 到 许 多 朋 友 的 询 问 , 所 以 决 定 花 一 些 时 间 试 着 解 决 这 个 重 要 的 问 题 。
增 加 应 用 程 式 载 入 的 效 率
如 果 我 们 仔 细 的 思 考 这 个 问 题 的 话 , 就 可 以 发 现 问 题 出 在 每 一 支 独 立 的 EXE 都 需 要 重 复 的 连 结 资 料 库 所 至 。 所 以 如 果 我 们 可 以 让 连 结 到 资 料 库 的 次 数 减 少 的 话 , 不 就 可 以 加 快 应 用 程 式 载 入 的 效 率 了 吗 ?
这 个 想 法 当 然 很 简 单 , 但 是 问 题 是 要 如 何 的 减 少 应 用 程 式 连 结 资 料 库 的 次 数 呢 ? 事 实 上 这 个 想 法 也 很 简 单 , 最 好 是 让 应 用 系 统 连 结 资 料 库 的 次 数 变 成 一 次 , 如 此 一 来 除 了 主 程 式 需 要 连 结 资 料 库 之 外 , 其 他 的 应 用 模 组 都 能 够 公 同 使 用 由 主 程 式 载 入 的 资 料 模 组 的 话 , 那 么 一 切 问 题 不 都 解 决 了 吗 ? 请 注 意 , 在 这 里 我 所 说 的 其 他 模 组 代 表 独 立 的 EXE 或 是 其 他 形 式 的 应 用 程 式 , 而 不 是 指 在 单 一 一 个 EXE 之 中 不 同 的 表 格 或 是 子 系 统 。
我 们 可 以 使 用 图 一 来 表 示 这 个 想 法 。 在 这 个 构 想 中 , 我 希 望 由 应 用 主 程 式 先 负 责 载 入 公 用 的 资 料 模 组 。 在 这 个 资 料 模 组 之 中 有 其 他 子 系 统 需 要 使 用 各 个 资 料 库 表 格 , 如 此 一 来 当 主 程 式 启 动 其 他 的 子 系 统 时 , 就 不 需 要 再 让 每 一 个 子 系 统 再 连 结 , 开 启 资 料 库 表 格 了 。

图一 公 用 资 料 模 组 示 意 图
当 这 样 还 有 一 些 设 计 上 的 问 题 , 我 们 稍 后 再 回 来 讨 论 这 个 问 题 , 现 在 先 我 们 看 看 如 何 的 把 这 个 构 想 实 做 出 来 , 并 且 测 试 一 下 实 际 的 结 果 是 不 是 真 的 比 较 有 效 率 。
要 实 做 这 个 构 想 , 我 们 必 须 想 办 法 让 公 用 的 资 料 模 组 能 够 让 每 一 个 子 系 统 存 取 到 , 并 且 不 再 需 要 每 一 个 子 系 统 都 分 别 的 和 资 料 库 建 立 一 个 连 结 的 Session。 我 的 第 一 个 想 法 是 使 用 DLL来 解 决 这 个 问 题 。 但 是 事 实 上 使 用 DLL无 法 解 决 这 个 问 题 。 在 我 花 费 了 许 多 的 时 间 之 后 , 使 用 DLL仍 然 有 会 有 Access Violation的 错 误 。 我 也 曾 在 网 路 上 搜 寻 相 关 的 问 题 或 是 资 料 , 我 在 宝 兰 的 Discuss Forum中 也 看 到 有 人 提 出 类 似 的 问 题 , 但 是 似 乎 都 没 有 人 确 实 的 回 答 这 个 问 题 。 我 也 想 过 干 脆 拿 出 我 的 Soft-Ice 和 Bounds-Checker 看 看 为 什 么 使 用 DLL Assembly 打 交 道 , 这 实 在 不 是 件 好 玩 的 事 情 。 正 打 算 放 弃 之 时 , 突 然 想 到 Delphi 3.0 之 中 的 Package 不 正 是 解 决 这 个 问 题 的 好 方 法 吗 ? 于 是 我 就 决 定 试 试 看 , 果 然 一 击 中 地 , 顺 利 的 解 决 了 这 个 问 题 。 当 然 , 要 知 道 为 什 么 使 用 Package 可 以 解 决 这 个 问 题, 你 需 要 知 道 Package 和 DLL 的 异 同 。
DLL 和 Package
为 什 么 在 我 一 开 始 使 用 DLL时 无 法 解 决 多 个 模 组 共 用 一 个 资 料 模 组 DLL的 问 题 呢 ? 这 主 要 是 因 为 在 Win 95/NT中 当 每 一 个 模 组 载 入 DLL时 , 对 于 每 一 个 DLL之 中 的 全 域 变 数 而 言 , 每 一 个 模 组 都 会 有 一 份 独 立 的 变 数 。 这 是 什 么 意 思 呢 ? 我 们 可 以 使 用 图 二 来 说 明 。

图 二 Win 95/NT 中 全 域 变 数 和 模 组 的 关 系
当 图 二 中 的 模 组 一 和 模 组 二 分 别 的 载 入 它 们 共 用 的DLL 时 , 虽 然 在 这 个 共 用 的 DLL 中 有 一 个 全 域 变 数gAccount 。 但 是 模 组 一 和 模 型 二 会 分 别 的 拥 有 一 个gAccount 变 数 。 这 也 就 是 说 模 组 一 对 于gAccount 变 数 数 值 所 做 的 修 改 并 不 会 影 响 模 组 二 中 的gAccount 变 数 数 值 。 在 Wn 95/NT 中 的DLL 行 为 是 和 Win 3.x 不 同 的 , 因 为 在 Win 3.x 中 所 有 的 模 组 都 使 是 共 用 一 份 DLL 中 的 全 域 变 数 。
由 于 Win 95/NT 中 DLL 全 域 变 数 的 这 种 特 性 , 所 以 当你 想 把 资 料 模 组 撰 写 在DLL 之 中 让 多 个 模 组 共 同使 用 时 , 问 题 就 来 了 。 因 为 在 这 种 情 形 下 , 每 一 个 模 组 都 会 有 一 份 它 自 己 的 资 料 模 组 。 所 以 当 每一 个 应 用 程 式 模 组 载 入 资 料 模 组 的 DLL 时 , 它 仍 然 会 连 结 资 料 库 一 次 , 所 以 你 并 无 法 减 少 连 结资 料 库 的 次 数 。
那 么 使 用 Package 有 什 么 不 同 吗 ? 在 回 答 这 个 问 题 之 前 , 请 你 先 回 想 一 下 。 在 Delphi 3.x 中 它 允 许 你 使 用 Package 的 功 能 来 编 译 你 的 应 用 程 式 , 如 图 三 所 示 。

图 三 Delphi 3.x 允 许 你 使 用Package 的 功 能 编 译 应 用 程序
使 用 Package 编 译 应 用 程 式 的 好 处 除 了 可 以 减 少 应 用 程 式 的 大 小 之 外 , 事 实 上 Package 还 有 一 个 很 重 要 的 特 性 , 那 就 是 Package 允 许 多 个 模 组 共 用 所 有 的 全 域 变 数 。
我 们 可 以 使 用 图 四 来 说 明 Package 的 特 性 。 请 你 想 一 想 , 当 你 的 应 用 程 式 使 用 Package 的 功 能 时 ,事 实 上 它 必 须 载 入 许 多 不 同 的 Packages 。 不 管 你 的 应 用 程 式 是 否 使 用 了 全 域 变 数 Application , 许 多 的 Packages 都 会 使 用 Application 这 个 全 域 变 数 。 由 于 全 域 变 数 Application 是 存 在 于 VCL.DPL 之 中 , 所 以 如 果 Application 会 对 于 每 一 个 载 入 它 的 模 组 都 产 生 一 份 独 立 的 全 域 变 数 的 话 , 那 么 整 个 应 用 程 式 便 会 产 生 不 正 确 的 结 果 。 所 以 由 这 个 说 明 我 们 可 以 知 道 , 在 图 四 中 的 Application 和 Screen 等 全 域 变 数 对 于 所 有 使 用 它 的 模 组 而 言 一 定 是 只 有 一 份 全 域 变 数 。

图 四 Package 中 全 域 变 数 的 特 性
事 实 上 在 Forms.PAS 之 中 的 程 式 码 也 透 露 着 这 些 蛛 丝 马 迹 。 例 如 下 面 便 是 Forms.PAS 宣 告 Application 和 Screen 这 二 个 变 数 的 程 式 码 。 从 它 们 的 注 释 中 我们 可 以 清 楚 的 看 到 , 它 们 是 全 域 物 件 , 即 使 是 编 译 成 Package 时 也 是 一 样 。
{ Global objects } varApplication: TApplicationScreen: TScreenCtl3DBtnWndProc: Pointer = nil;
由 于 Package 能 够 自 动 的 将 其 中 的 全 域 变 数 编 译 成 所 有 使 用 它 的 模 组 都 共 用 一 份 的 特 性 。 所 以 我 们 就 可 以 使 用 这 个 特 性 重 新 的 建 构 图 一 的 架 构 成 为 图 五 的 形 式 。

图 五 改 良 过 的 公 用 资 料 模 组 示 意 图
在 图 五 中 我 们 可 以 把 所 有 模 组 需 要 共 同 使 用 的 资 料 模 组 撰 写 在 一 个 Package 之 中 , 然 后 再 把 每 一 个 子 系 统 撰 写 成 独 立 的 Package 。 只 有 主 程 式 是 EXE , 它 负 责 载 入 共 用 的 资 料 模 组 , 以 及 在 使 用 者 启 动 每 一 个 子 系 统 时 再 载 入 相 对 应 的 子 系 统 Package 。
使 用 这 种 架 构 有 许 多 的 好 处 。 第 一 个 便 是 共 用 的 资 料 模 组 只 需 要 载 入 一 次 即 可 。 而 这 个 好 处 便 是 我 们 前 面 讨 论 需 要 解 决 的 问 题 。 如 此 一来 在 每 一个 子 系 统 载 入 时 便 可 以 加 快 其 执 行 的 速 度 。 第 二 个 好 处 是 在 开 发 这 整 个 系 统 时 , 我 们 仍 然 可 以 让不 同 的 程 式 师 负 责 发 展 不 同 的 子 系 统 , 这 样 可 以 就 可 以 解 决 前 面 讨 论 的 分 工 的 问 题 。 此 外 如 果 一 个 子系 统 很 庞 大 的 话 , 你 也 可 以 再 次 的 切 割 这 个 子 系 统 成 为 更 多 的 小 系 统 。 例 如 你 可 以 再 把 图 五中 的 会 计 子 系 统 Package 再 分 为 一 般 会 计 , 成 本 会 计 , 和 管 理 会 计 等 不 同 的 Package 。 第 三 个 好 处 是 使 用 Package 就 像 是 使 用 DLL 一 样 , 主 程 式 可 以 在 需 要 的 时 候 才 载 入 一 个 Package , 在 使 用 完 毕 之 后 可 以立 刻 的 释 放 这 个 Package , 这 样 可 以 让 你 对 于 系 统 资 源 有 更 好 的 控 制 能 力 。 最 后 一 个 好 处 是 使 用 Package 可 以 让 你 发 展 出 Plug-and-Play 的 模 组 , 当 然 这 需 要 藉 由 结 合 虚 拟 介 面 或 是 虚 拟 类 别 的 功 能 。 藉 由 使 用 Package 和 虚 拟 介 面 的 能 力 , 你 可 以 任 意 的 替 换 应 用 系 统 之 中 的 模 组 而 不 会 影 响 系 统 的 执 行 。 这 个 功 能 对 于 许 多 使 用 Delphi 开 发 套 装 软 体 的 程 式 师 来 说 是 一 个 非 常 重 要 的 功 能 。
现 在 你 应 该 对 于 DLL 和 Package 的 差 异 有 了 基 本 的 瞭 解 , 现 在 是 让 我 们 看 看 如 何 使 用 Package 的 特 性 解 决 我 们 面 对 的 问 题 的 时 候 了 。 下 一 小 节 就 让 我们 实 际 的 撰 写 一 个 范 例 来 证 明 Package 对 于 全 域 变 数 的 处 理 方 式 以 及 使 用Package 的 确 能 够 加 快 应 用 程 式 的 载 入 速 度 。
实 际 的 范 例
由 于 平 日 我 大 部 份 的 时 间 都 是 使 用 Oracle , MS SQL Server 和 InterBase (许 多 的 读 者 都 询 问 我 为 什 么 不 使 用Sybase 或 是 Informix 做 为 范 例 说 明 , 这 实 在 是 因 为 我 比 较 少 使 用 它 们 , 并 没 有 其 他 的 意 思 , 所 以 请使 用 Sybase ,Informix 和 DB2 的 读 者 见 谅 。 不 过 我 相 信 我 们 讨 论 的 东 西 都 可 以 使 用 在 这 些 资 料 库 之 上) 。 在 这 三 个 资 料 库 中 , Oracle 的 连 结 速 度 一 直 都是 令 我 非 常 头 大 的 , 因 为 在 这 三 者 之 中 ,Orcale 连 结 资 料 库 和 开 启 资 料 库 表 格 的 时 间 最 久 。 所 以 本 节 的 范 例 就 以 Oracle 资 料 库 为 范 例 , 看 看 使 用 了Package 之 后 会 不 会 有 任 何 明 显 的 改 善 。
首 先 请 你 先 建 立 一 个 Package , 并 且 在 这 个 Package 之 中 产 生 一 个 资 料 模 组 , 并 且 使 用 Database 和 Query 元 件 连 结 到 Oracle 的 资 料 库 如 图 六 所 示 。

图 六 存 在 于 Package 之 中 的 资 料
模 组 使 用 Database 连 结到 Oracle
在 成 功 的 编 译 了 这 个 Package 之 后 , 再 让 我 们 设 计 范 例 程 式 的 主 表 格 如 图 七 一 样 。

图 七 使 用 公 用 资 料 模 组 的 主 表 格
在 主 表 格 中 有 一 个 DataSource 元 件 。 这 个 DataSource 组件 会 在 资 料 模 组 的 Package 载 入 之 后 , 连 结 到 资料 模 组 之 中 的 Query 元 件 以 便 显 示 Oracle 资 料 库 之 中的 资 料 。 现 在 剩 下 的 工 作 便 是 撰 写 程 式 码 载 入 资 料 模 组 Package 和 显 示 资 料 库 的 资 料 。
首 先 在 主 表 格 启 动 时 , 它 必 须 在 FormActivate 事 件 处 理 函 数 中 载 入 资 料 模 组 Package 。 它 呼 叫 LoaddbPackage 这 个 程 序 。
procedure TMainForm.FormActivate(Sender: TObject);
begin
LoaddbPackage;
end;
LoaddbPackage 是 真 正 负 责 载 入Package 的 程 序 。 它 在 一 个 try except 程 式 区 块 中 呼 叫 Delphi 的 LoadPackge 函 数 载 入 指 定 名 称 的 Package 。 这 个 函 数 在 成 功 执 行 后 会 回 传 一 个 Package 的 handle 值 。 我 们 的 程 式 必 须 储 存 这 个 handle 值 以 便 稍 后 使 用 它 , 并 且 在 最 后 藉 由 这 个 handle 值 释 放 载 入 的 Package 。 如 果 呼 叫 LoadPackage 成 功 的 话 , 程 式 就 呼 叫 LoadDataModule 从Package 中 取 得 前 面 介 绍 的 资 料 模 组 , 否 则 在 except 程 式 区 块 中 ShowMessage 会 显 示 发 生 错 误 的 原 因 。
procedure TMainForm.LoaddbPackage;
begin
//我们必须加载数据库Package以便连结到数据库tryaDBConnect := LoadPackage(DBPackages);LoadDataModule;excepton E : Exceptiondo
begin
MessageBeep(Word(-1));ShowMessage(E.Message);Application.Terminate;
end;
end;
end;
在 LoadDataModule 中 我 们 必 须 先 从 资 料 模 组 Package 之 中 取 得 资 料 模 组 的 真 正 Meta-Class 名 称 , 然 后 使 用 这 个 Meta-Class 建 立 真 正 的 资 料 模 组 物 件 。 所 以 LoadDataModule 一 开 始 会 呼 叫 GetClass 向 Windows 取 得 特 定 类 别 名 称 的 Meta-Class 。 而 GetClass 传 入 的 参 数 『TConcreteDataModule』 , 便 是 前 面 我 们 建 立 的 资 料 模 组 的 真 正 的 类 别 名 称 。
由 于 一 个 独 立 的 EXE 要 能 够 取 得 Package 之 中 的 Meta-Class 必 须 使 用 指 定 的 类 别 名 称 。 所 以当 你 在Package 中 撰 写 任 何 的 类 别 时 , 你 必 须 确 定 这 个 类 别 名 称 在 所 有 Delphi 或 是 应 用 程 式 载 入 的 Package 中 都 是 唯 一 的 。 否 则 如 果 有 在 所 有 载 入 的 Pakcage 中 有 相 同 的 类 别 名 称 时 ,Delphi 或 是 应 用 程 式 会 产 生 一 个 例 外 。
在 成 功 的 从 Package 取 得 了 Meta-Class 之 后 , 你 就 必 须 使 用 这 个 Meta-Class 产 生 真 正 的 资 料 模 组 物 件 。 请 注 意 在 下 面 的 程 式 码 中 , 我 们 使 用 了 强 制 型 态 转 换 把 TComponentClass 的 物 件 转 换 为 TDataModule 的 物 件 。
在 建 立 了 TDataModule 物 件 之 后 , 我 们 就 可 以 一 一 的 搜 寻 资 料 模 组 之 中 的 元 件 并 且 找 到 我 们 需 要 的 Query 元 件 , 并 且 把 主 表 格 中 DataSource 的 DataSet 特 性 值 设 定 为 找 到 的 Query 元 件 。
procedure TMainForm.LoadDataModule;var iCounter : Integer;
begin
{ Note that TApplication "owns" this form and thus it must be freed priorto unloading the package }dataModuleClass := GetClass('TConcreteDataModule');
if dataModuleClass <> nil then
begin
admGlobal :=TDataModule(TComponentClass(dataModuleClass).Create(Application));for iCounter := 0 to admGlobal.ComponentCount - 1do
begin
if UpperCase(admGlobal.Components[iCounter].ClassName) = 'TQUERY' then
begin
aQuery := TQuery(admGlobal.Components[iCounter]);DataSource1.DataSet := aQuery;break;
end;
end;
end;
end;
由 于 在 上 面 的 程 式 码 中 我 们 使 用 了 GetClass 以 取 得 特 定 名 称 的 Meta-Class , 所 以 你 的 资 料 模 组 Package 必 须 在 它 的 initialization 程 式 区 块 中 先 注 册 它 自 己 。 下 面 的 程 式 码 便 是 资 料 模 组 Package 注 册 的 程 式 码 。
initializationRegisterClass(TConcreteDataModule)
现 在 就 可 以 执 行 范 例 程 式 了 , 在 主 程 式 执 行 之后 , 你 可 以 看 到 类 似 图 八 的 画 面 。 从 主 表 格 中 我 们 可 以 证 明 的 确 可 以 藉 由 资 料 模 组 Package 存 取 到 Oracle 的 资 料 。

图 八 主 表 格执 行 的 画 面 , 它 果 然
可 以 藉 由 资 料 模 组 Package 存 取 资 料
到 这 里 为 止 我 们 只 是 证 明 了 使 用 资 料 模 组 Package可 以 让 应 用 程 式正 确 的 执 行 , 但 是 主 程序 启 动 的 时 间 和 一 般 独 立 的 EXE 没 有 什 么 不 同 。 但 是 接 下 来 的 情 形 就 比 较 有 趣 了 。 因 为 我 们 要 藉 由 接 下 来 的 程 式 码 来 证 明 使 用 Package 可 以 大 幅 加 快 子 系 统 的 载 入 速 度 。
在 主 表 格 中 有 一 个 按 钮 『载 入 第 二 个 UI Package』 。 这 个 按 钮 的 功 能 就 是 模 拟 载 入 子 系 统 的 功 能 。 当 使 用 者 点 选 这 个 按 钮 之 后 , 范 例 程 式 会 载 入 另 外 一 个 只 有 使 用 者 介 面 的Package , 而 且 这 个 Package 必 须 再 使 用 刚 才 载 入 的 资 料 模 组Package 来 显 示 资 料 。 藉 由 这 个 模 拟 的 子 系 统 功 能 , 我 们 要 证 明 资 料 模 组 Package 可 以 在 不 同 的 模 组 中 共 用 而 且 可 以 加 快 模 组 启 动 的 时 间 。
这 个 按 钮 的 OnClick 事 件 处 理 函 数 和 主 表 格 的 FormActvate 事 件 处 理 函 数 非 常 的 类 似 , 它 也 是 呼 叫 LoadUIPackage 程 序 以 便 载 入 一 个 使 用 者 介 面 Package 。
procedure TMainForm.Button1Click(Sender: TObject);
begin
LoadUIPackage;
end;
LoadUIPackage 和 LoaddbPackage 几 乎 一 模 一 样 , 它 也 是 呼 叫Delphi 的 LoadPackage 和 GetClass 载 入 Package , 取 得 使 用 者 介 面 表 格 的 Meta-Class , 建 立 使 用 者 介 面 表 格 对象 , 搜 寻 资 料 模 组 中 的 Query 元 件 , 然 后 显 示 资 料 库 的 资 料 。
procedure TMainForm.LoadUIPackage;
begin
//我们必须加载使用者接口Package以便连结到数据库tryUIConnect := LoadPackage(UIPackages);LoadUIModule;excepton E : Exceptiondo
begin
MessageBeep(Word(-1));ShowMessage(E.Message);Application.Terminate;
end;
end;
end;
procedure TMainForm.LoadUIModule;variCounter : Integer;aDS : TDataSource;
begin
{ Note that TApplication "owns" this form and thus it must be freed priorto unloading the package }pkgModuleClass := GetClass('TUIPackageForm');
if pkgModuleClass <> nil then
begin
aPkgForm := TCustomForm(TComponentClass(pkgModuleClass).Create (Application));for iCounter := 0 to aPkgForm.ComponentCount - 1do
begin
if UpperCase(aPkgForm.Components[iCounter].ClassName) = 'TDATASOURCE' then
begin
aDS := TDataSource(aPkgForm.Components[iCounter]);aDS.DataSet := aQuery;break;
end;
end;
aPkgForm.Visible := True;
end;
end;
当 我 们 完 成 载 入 使 用 者 介 面 Package 的 功 能 , 再 执 行 范 例 程 式 并 且 按 下 『载 入 第 二 个 UI Package』 按 钮 之 后 , 可 以 看 到 类 似 图 九 的 画 面 。

图 九 第 二 个 使 用 者 介 面 Package 启 动 的 画 面
令 人 惊 讶 的 是 , 使 用 者 介 面 Package 之 中 的 表 格 会 立 刻 的 显 示 出 来 , 几 乎 完 全 不 需 要 等 待 。 表 格 一 是 我 使 用 这 个 范 例 程 式 和 使 用 二 个 独 立 的 EXE 应 用 程 式 比 较 的 结 果 。 从 表 格 中 你 可 以 看 到 使 用Package 载 入 子 系 统 比 使 用 EXE 载 入 子 系 统 整 整 快 了 十 倍 。
  使 用 独 立 的EXE 应 用 程 式 使 用EXE 加Package 的 功 能
主 程 式 启 动 时 间 20 20
其 余 模 组 启 动 时 间 20 2
表 格 一 独 立 的 EXE 和 使 用 Package 的 EXE 执 行 的 效 率 比 较

图十 使 用Package 的 应 用 程 式 和 一 般 应 用 程 式 执 行 效 率 的 比 较
从 上 面 的 结 果 我 们 就 可 以 知 道 使 用 Package 的 好 处 , 它 不 但 可 以 让 我 们 共 用 资 源 , 也 能 够 改 善 子系 统 启 动 的 时 间 。
当 然 应 用 程 式 在 使 用 完 毕 之 后 , 它 必 须 释 放 动 态 载 入 的 Package 以 便 释 放 系 统 资 源 。 在 主 表 格 的 FormClose 事 件 处 理 函 数 中 它 呼 叫 了 UnLoadAddInPackage 程 序 并 且 传 递 Package 的 handle 值 做 为 参 数 以 便 释 放 Package 。
procedure TMainForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
UnLoadAddInPackage(dbConnect);UnLoadAddInPackage(UIConnect);
end;
UnLoadAddInPackage 先 从 全 域 物 件 Application 中 找 到 载 入 的 资 料 模 组 和 使 用 者 介 面 表 格 , 先 释 放 这 些 动态 载 入 , 建 立 的 物 件 , 切 断 它 们 和Application 和 关 系 , 再 利 用 Package 的 handle 值 解 除 Package 对 Windows 的 注册 , 最 后 再 呼 叫 UnLoadPackage 释 放 载 入 到 记 忆 体 之 中 的 Package 。
procedure UnLoadAddInPackage(Module: THandle);var i: Integer;M: TMemoryBasicInformation;
begin
for i := Application.ComponentCount - 1do
wnto 0do
begin
VirtualQuery(GetClass(Application.Components.ClassName), M, SizeOf(M));
if (Module = 0) or (HMODULE(M.AllocationBase) = Module) then
begin
ShowMessage(Application.Components.ClassName);Application.Components.Free;
end;
end;
UnRegisterModuleClasses(Module);UnLoadPackage(Module);
end;
当 你 结 束 主 程 式 时 , 你 应 该 会 看 到 类 似 图 十 一 和图 十 二 的 画 面 。 这 些 画 面 证 明 了 当 主 程 式 结 束 时 , 它 能 够 正 确 的 释 放 所 有 载 入 的 Package 以 释 放 系 统 资 源 。

图 十 一 范 例 程 式 结 束 时 显 示 它 正 确 的 释 放 了 所 有 使 用 的 Package

图 十 二 范 例 程 式 正 确 的 释 放 了 公 用 的 资 料 模 组 Package
上 面 的 范 例 程 式 证 明 了 使 用 Package 的 确 能 够 公 用 Package 以 及 Package 之 中 的 全 域 资 料 , 此 外 也 能 够 帮 助 子 系 统 加 快 载 入 和 启 动 的 时 间 。 但 是 主 程 式 在 启 动 时 仍 然 需 要 载 入 资 料 模 组 Package , 连 结 资 料 库 。 但 是 对 于 许 多 的 使 用 者 而 言 , 他 们 仍 然 会 希 望 让 主 程 式 也 能 够 很 快 的 出 现 。 要 达 成 这 个 目 标 , 你 还 需 要 藉 助 Delphi 执 行 绪 的 能 力 。
加 入 多 执 行 绪 载 入 的 能 力
在 上 一 节 中 你 看 到 了 使 用 Package 的 确 可 以 大 幅 加 快 子 系 统 载 入 的 时 间 。 但 是 我 们 在 载 入 主 程 式 时 仍 然 需 要 20 到 30 秒 的 时 间 , 因 为 主 程 式 还 是 需 要 载 入 共 用 的 资 料 模 组 Package 。 但 是 对 于 许 多 案 子 来 说 , 使 用 者 经 常 会 要 求 程 式 必 须 在 10 秒 或 是 5 秒 之 内 第 一 个 画 面 就 必 须 出 现 。 那 么 对 于 这 种 要 求 我 们 可 不 可 以 达 到 呢 ?
如 果 你 想 到 Delphi 中 的 多 工 执 行 绪 功 能 Tthread 物 件 的 话 , 那 么 答 案 就 出 现 了 。 我 们 只 需 要 在 主 程序 第 一 个 表 格 出 现 之 时 , 启 动 一 个 多 执 行 绪 物 件 让 它 负 责 载 入 公 用 的 资 料 模 组 不 就 可 以 了 吗 ? 如 此 一 来 主 表 格 可 以 立 刻 的 出 现 在 萤 幕 之 上 , 而 让 执 行 绪 在 背 景 继 续 的 载 入 资 料 模 组 。
为 了 要 加 入 多 执 行 绪 的 能 力 , 你 必 须 修 改 上 一 节 的 范 例 。 在 范 例 程 式 的 FormActivate 事 件 处 理 函 数 我 们 不 再 直 接 呼 叫 LoaddbPackage , 而 是 建 立 一 个 Tthread 物 件 , 然 后 由 这 个 Tthread 物 件 真 正 的 载 入 资 料 模 组 Package 。
procedure TMainForm.FormActivate(Sender: TObject);
begin
DBThread := TOracleThread.Create(True);aDBThread.OnTerminate := dbThreadTerminated;aDBThread.Resume;
end;
在 TOracleThread 的 Execute 虚 拟 方 法 中 , 它 呼 叫 了 LoaddbPackage 载 入 资 料 模 组 。 在 这 里 有 一 点 非 常 重 要 的 地 方 便 是 当 你 在 执 行 绪 中 载 入 Package 时 , 所 有 的 handle 值 和 物 件 参 考 值 必 须 储 存 在 主 执 行 绪 的 变 数 之 中 。 否 则 在 这 个 执 行 绪 执 行 完 毕 之 后 , 这 些 handle 值 和 物 件 参 考 值 都 会 成 为 无 效 的 数 值 。 所 以 在 下 面 的 程 式 码 中 你 可 以 看 到 执 行 绪 在 呼 叫 LoadPackage 载 入 Package 时 会 把 LoadPackage 回 传 的 数值 储 存 在 主 表 格 的 变 数 之 中 。
procedure TOracleThread.Execute;
begin
{ Place thread code here }LoaddbPackage;
end;
procedure TOracleThread.LoaddbPackage;
begin
//我们必须加载数据库Package以便连结到数据库tryMainForm.aDBConnect := LoadPackage(DBPackages);LoadDataModule;excepton E : Exceptiondo
begin
MessageBeep(Word(-1));ShowMessage(E.Message);Application.Terminate;
end;
end;
end;
procedure TOracleThread.LoadDataModule;variCounter : Integer;
begin
{ Note that TApplication "owns" this form and thus it must be freed priorto unloading the package }dataModuleClass := GetClass('TConcreteDataModule');
if dataModuleClass <> nil then
begin
MainForm. admGlobal:= TDataModule(TComponentClass(dataModuleClass).Create(Application));
end;
end;
当 我 们 修 改 完 范 例 程 式 之 后 , 就 可 以 试 着 再 次 的执 行 它 , 看 看 主 程 式 的 载 入 时 间 是 不 是 有 任 何 的 改 善 。 下 面 的 表 格 和 图 形 显 示 出 当 我 们 使 用 了 执行 绪 的 功 能 之 后 , 第 一 支 主 程 式 启 动 的 时 间 果 然大 幅 减 少 为 3 秒 钟 。 比 起 原 来 的 20 秒 果 然 改 善 了 许 多 , 真 是 令 人 印 象 深 刻 。
  使 用 独 立 的 EXE 应 用 程 式 使 用EXE 加Package 的 功 能
主 程 式 启 动 时 间 20 3
其 余 模 组 启 动 时 间 20 2
表 格 二 使 用 执 行 绪 后 的 范 例 程 式 执 行 效 率

图 十 三 加 入 执 行 绪 后 应 用 程 式 执 行 的 效 率
现 在 使 用 了 执 行 绪 功 能 之 后 , 不 但 每 一 个 子 系 统启 动 的 时 间 加 快 了 许 多 , 主 程 式 更 是 可 以 在 瞬 间出 现 , 这 样 的 执 行 速 度 应 该 是 可 以 让 大 部 份 的 人满 意 了 吧 。
应 用 程 式 , 企 业 法 则 (企 业 物 件) 的 切 割
从 上 面 的 范 例 中 我 们 可 以 知 道 , 善 用 Delphi 的 Package 和 执 行 绪 的 功 能 可 以 让 我 们 大 幅 的 改 善 应 用 程 式 载 入 和 执 行 的 效 率 。 但 是 上 面 的 范 例 只 是 假 设 在 很 简 单 的 状 态 之 下 。 在 许 多 实 际 的 案 子 中 , 我 们 可 能 无 法 把 所 有 的 资 料 集 元 件 放 在 一 个 单 一 的 资 料 模 组 之 中 。 在 这 种 情 形 下 , 你 可 以 把 所 有 的 资 料 集 元 件 分 别 撰 写 在 不 同 的 资 料 模 组 Package 之 中 , 并 且 在 每 一 个 子 系 统 需 要 特 定 的 资 料 模 组 Package 时 再 载 入 它 们 。
当 我 们 从 这 个 角 度 观 察 应 用 系 统 时 , 可 以 发 现 如 何 的 切 割 资 料 集 到 不 同 的 资 料 模 组 中 似 乎 是 一 件 非 常 重 要 的 事 情 。 因 为 这 不 但 牵 涉 到 应 用 系 统 执 行 的 效 率 , 更 和 系 统 资 源 的 善 用 有 很 大 的 关 系 。 事 实 上 当 我 们 开 发 N-Tier 的 应 用 系 统 时 , 你 也 会 发 现 如 何 切 割 应 用 程 式 和 企 业 物 件 对 整 个 应 用 系 统 的 架 构 有 深 远 的 影 响 。
所 以 应 用 程 式 和 企 业 物 件 的 切 割 似 乎 在 未 来 新 一 代 应 用 系 统 的 开 发 中 占 有 重 要 的 地 位 。 当 然要 能 够 适 当 , 有 效 率 的 切 割 企 业 物 件 需 要SA 在 分 析 系 统 时 好 好 的 做 分 析 的 工 作 , 更 需 要 SD 能 够 通 盘 的 设 计 整 个 应 用 系 统 运 作 的 架 构 。
如 果 我 们 结 合 Delphi 强 大 的 N-Tier ,Package 以 及 执 行 绪 功 能 的 话 , 就 可 以 使 用 如 下 的 图 形 来 表 示 。

图 十 四 N-Tier , Package 和 执 行 绪 结 合 使 用 的 架 构
请 注 意 在 图 十 四 中 说 明 了 并 不 是 只 有 资 料 模 组 可 以 存 在 于 Package 之 中 , 我 们 也 可 以 把 应 用 逻 辑 或 是 企 业 物 件 封 装 在 Package 之 中 或 是 ActiveX 之 中 , 于 应 用 程 式 需 要 时 再 载 入 执 行 它 们 。 最 后 由 于 应 用 程 式 伺 服 器 在 大 多 数 的 情 形 下 是 执 行 在Windows NT Server 之 中 , 所 以 我 们 可 以 更 有 效 率 的 使 用 作 业 系 统 的 执 行 绪 能 力 来 载 入 应 用 程 式 需 要 的 Package 。
更 具 威 力 的 功 能
就 像 我 在 前 面 说 明 的 , 我 无 法 在 一 篇 文 章 中 为 各 位 介 绍 所 有 有 关 Package 的 使 用 方 法 和 各 种 功 能 。 使 用 Package 更 高 阶 和 更 具 威 力 的 功 能 应 该 是 和 虚 拟 类 别 结 合 一 起 使 用 。 此 外 Delphi 3 也 提 供 了 许 多 的 程 序 和 函 数 能 够 让 你 检 查 每 一 个Package 使 用 了 什 么 其 他 的Package , 执 行 时 期 函 式 馆 和 全 域 函 式 。
结 合Package 和 虚 拟 类 别 不 但 能 够 让 你 发 展 出 Plug-and-Play 的 模 组 功 能 , 更 能 够 让 你 完 全 的 控 制Package 中 所 有 的 物 件 和 变 数 。 更 能 够 让 你 发 展 出 一 些 自 动 化 的 工 具 来 帮 助 你 开 发 你 的 应 用 系 统 。 我 计 划 在 以 后 的 文 章 中 再 继 续 和 各 位 讨 论 这 些 高 等 的 主 题 。
结 论
在 本 篇 文 章 中 我 们 看 到 了 如 何 的 使 用 Delphi 3.0 中的Package 功 能 来 解 决 应 用 载 入 时 连 结 资 料 库 效 率 的 问 题 。 许 多 人 对 于 Package 的 认 识 只 是 它 可 以 减 少 应 用 程 式 的 檔 案 大 小 , 除 此 之 外 似 乎 就 没 有 什 么 其 他 的 瞭 解 了 。 但 是 这 篇 文 章 就 告 诉 你 如 何 的 发 掘 Package 更 有 威 力 的 一 个 应 用 。 使 用 Packages 可 以 立 刻 的 降 低 模 组 启 动 需 要 的 时 间 。
但 是 我 们 在 这 篇 文 章 中 就 讨 论 了 所 有 有 关Package 的 功 能 来 吗 ? 那 当 然 不 , 还 需 要 许 多 更 有 威 力 的 功 能 我 并 未 讨 论 。 例 如 你 如 果 能 够 更 进 一 步 的 结 合 Package , 参 考 计 数 值 以 及 抽 象 虚 拟 类 别 (Abstract Virtual Class) 或 是 抽 象 介 面 的 话 , 那 么 你 就 可 以 完 全 的 控 制 Package 中 内 含 的 类 别 以 及 表 格 , 而 不 需 要 一 定 是 Delphi 内 定 的 类 别 和 表 格 。 这 样 一 来 你 可 以 设 计 一 个 Plug-and-Play 的 Package 介 面 , 以 便 让主 程 式 能 够 载 入 任 意 的 Package , 存 取 它 功 能 。 此 外 你 也 可 以 取 得 Package 中 许 多 重 要 的 资 讯 , 例 如 这 个 Package 输 出 了 那 些 的 方 法 , 使 用 了 那 些 其 他 的 Package ?Package 和 initialize 以 及 finalization 的 关 系 等 , 也 许 有 机 会 再 让 我 们 讨 论 这 些 更 有 意 思 的 主 题 。
事 实 上 从 这 篇 文 章 中 就 可 以 出Delphi 的 多 么 的 好 用 。 如 果 今 天 你 是 使 用 Visual Basic 或 是 PowerBuilder 的话 , 那 么 抱 歉 , 你 绝 对 无 法 解 决 这 个 问 题 , 也 许 再 等 到 下 一 个 Visual Basic 或 是 PowerBuilder 版 本 的 话 , 就 有 『可 能』 解 决 这 个 问 题 吧 。 但 是 Delphi 就 不 同 了 , 它 除 了 可 以 让 你 撰 写 一 般 的 应 用 系 统 , 但 是 在 遇 到 特 殊 的 情 形 时 , Delphi 也 可 以 在 短 暂 的 时间 内 超 越 工 具 目 前 功 能 的 限 制 , 而 解 决 这 些 问 题 , 谁 是 比 较 好 的 主 从 架 构 开 发 工 具 就 不 言 自 明 了 。
 
http://www2.borland.com.tw/tw/reference9.html
 
后退
顶部