65.9K
CodeProject 正在变化。 阅读更多。
Home

重构角落:分区 DataWindow 技术

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2011 年 10 月 20 日

CPOL

7分钟阅读

viewsIcon

11979

一个分区良好的应用程序将为将来的代码迁移到其他 GUI 平台铺平道路。

PowerBuilder 经典应用程序重构的主要目标之一是将代码划分为逻辑分区。尽管您可能不会因您的努力而获得显著的性能提升,但您将获得另外两个非常显著的收益。首先,您的逻辑将获得互操作性;您将能够与其他使用其他 .NET 语言开发的应用程序共享应用程序业务和数据逻辑。(我说“能够”是因为您仍然需要使您的方法接口符合通用类型系统。)其次,由于代码新获得的清晰度,您的代码维护活动将获得更可预测且更不容易出错的结果。

图 1 显示了重构前典型经典应用程序的概念结构。请注意,业务逻辑和数据访问逻辑都嵌入在 GUI 元素中。

Yakov-fig-1.jpg

图 2 描绘了重构后的典型概念结构。需要注意的重要特征是 GUI 与业务逻辑和数据访问逻辑解耦。业务逻辑所需的任何数据都通过调用数据访问分区中的类来获取。在这种架构中,GUI 可以成功地与数据库断开连接。

Yakov-fig-2.jpg

DataWindow 的挑战

如果您仔细查看图 2,您会注意到数据逻辑和 GUI 之间没有流。等等!DataWindow 呢?数据是如何显示在 GUI 上的?众所周知,DataWindow 是 PowerBuilder 首选的纯机制,用于显示和与数据库中的数据集交互,其用途远远超出向业务逻辑提供数据。该图没有显示数据逻辑层和 GUI 之间的连接。为什么?

Yakov-fig-3_0.jpg

DataWindow 对分区构成挑战,因为其内部结构抵制分区。澄清一下 - DataWindow 对象是一个自包含的智能对象,由其自身的两个逻辑层组成:表示层和数据源层。这两个层通过其元素之间的映射链接,该映射指定哪些数据源元素链接到哪些表示元素。图 3 显示了在 DataWindow Painter 的“列规范”视图中看到的映射。如果您怀疑我,请注意 DataWindow 工具实际上由两个工具组成:一个用于定义表示,另一个用于定义数据源。此外,表示层有自己的脚本语言和表达式评估引擎,用于定义 GUI 层行为和动态特性。当您将 DataWindow 对象与控件关联时,您将获得与表示层和数据层 API 交互编码的能力。最重要的是,您调用 SetTransObject(  ) 以通过控件将 DataWindow 的数据源层直接链接到数据库。从所有这些您可以清楚地看到,将 DataWindow 放置在窗口上会有效地在多个级别上破坏我们的分区方案。问题亟待解答:我们如何有效地分区 DataWindow?

答案在于 DataWindow API 本身,它具有支持分区的几种机制。使用这些 API,您可以将表示“标记”和 GUI 逻辑放置在 GUI 层中,并将数据访问逻辑放置在数据层中。有两种可能的方法,选择哪种方法取决于您的最终目标。如果您的目标是保留在单个应用程序中但具有分区代码,请使用 ShareData(  ) 机制来实现您的目标。如果您的目标是将 DataWindow 分拆到单独的程序集中,以便与外部 .NET 代码进行互操作,那么 DataWindow 同步 API 是您的选择(假设您在 Visual Studio 应用程序中使用 DataWindow .NET)。我现在将介绍单一分区应用程序方法;我将在另一篇文章中探讨互操作性。

ShareData

ShareData API 已经存在很久了。它允许您拥有多个 DataWindow 或 DataStore 演示连接到单个缓冲区集。它非常棒,因为它内存效率高,并且效果是即时的。您将一个数据控件指定为主控件,其余的成为辅助控件。只有一个数据集驱动所有演示。共享的 DataWindow 对象可以具有不同或相同的演示样式。需要注意的是,它们必须都具有共同的数据源定义。启用 ShareData 后,共享缓冲区中数据的任何更改都会反映在所有演示中。您可以利用此机制来支持逻辑分区。

基本技术是将主 DataWindow 对象包装在数据访问层自定义类用户对象中的 DataStore 中。所有演示层 DataWindow 都成为辅助控件。将 GUI 层与数据库断开连接,并从数据访问组件共享数据到 GUI,然后将您的数据访问层代码写入(或移动)到组件内部,必要时通过方法调用将其公开。此逻辑包括更新、检索和 DBError 事件处理逻辑。您应该将 GUI 演示层的特定细节(例如修改和描述调用、属性表达式、数据输入验证规则和导航逻辑)保留在 GUI 层中。您还可以将数据输入验证规则和视觉属性设置保留在 DataWindow 对象语法中。

限制

就像这个世界上的所有事物一样,并非所有都是纯粹的幸福。存在局限性。好消息是,对于大多数局限性,代码变通方法是可能的。我将在下一节中描述它们。

共享父 DataWindow 时,子 DataWindow 不会被共享。此限制有两个影响。首先,DropDownDataWindow 不会在辅助控件中自动填充。解决方法是,您需要从数据组件中的单独 DataStore 中检索 DropDown,并将其与 GUI 中的 DropDown 共享。为避免数据分区中重复和不必要的子数据检索,您应该在主 DataWindow 对象的定义中关闭 AutoRetrieve 属性。在 GUI 层中,在父 DataWindow 上编码共享后,使用 GetChild(  ) 填充 DropDown,使其成为数据访问层中其主伙伴的辅助 DataWindow。

其次,与 DropDown DataWindow 问题类似,复合 DataWindow 中的嵌套 DataWindow 不会共享。如果 GUI 具有复合 DataWindow 演示,则直接共享复合 DataWindow 没有意义。您将在数据组件中浪费时间检索它,因为没有任何内容被共享。相反,将复合 DataWindow 及其所有嵌套 DataWindow 对象放置在 GUI 层中。在数据访问层中复制嵌套 DataWindow。将所有嵌套 DataWindow 检索到 DataStore 中,然后将其与 GUI 层中的伙伴共享。

第三,交叉表 DataWindow 对象不可共享,句号。将具有交叉表演示的数据控件指定为辅助控件将失败。解决方法是使用 DataWindow 同步 API GetFullState(  )SetFullState(  )。在数据组件中,使用交叉表演示 DataWindow 对象检索到 DataStore 中。然后调用 GetFullState 将演示和数据获取到一个 blob 中。接下来,返回 blob。在 GUI 端,调用 SetFullState 将 blob 应用到一个空的 DataWindow 控件。此方法有两个缺点。第一,它会占用双倍内存,因为这里实际上有两个数据集。第二,数据不会在控件之间自动同步,因此对“主”控件的更改不会自动反映在 GUI 层中。图 4 显示了同步代码。

Yakov-fig-4_0.jpg

最后,当您共享数据时,无法为辅助 DataWindow 打开查询模式。如果您的 DataWindow 依赖于 QueryMode 允许用户指定 WHERE 子句条件,则您必须重新设计查询机制。尝试设置 QueryMode 或 QuerySort DataWindow 对象属性会导致错误。

特别说明

为了在 CCUO 中从主控件共享时节省内存和提高性能,您可以从数据访问层的主 DataWindow 对象中删除 GUI 层。为此,首先通过执行 SaveAs 到 DataAcess PBL 来创建 DataWindow 对象定义的匹配副本。添加一个后缀,例如 _nv 到名称中,以便您可以关联成对。在布局画板中选择所有并删除。DataWindow 对象名称将保留,但对象将从 GUI 中消失。还要将所有条带的高度设置为零。最后,确保关闭任何可能已设置其 AutoSize height 属性的条带。您只对缓冲区定义感兴趣。

结论

本次练习的目的是向您展示,通过一点代码重构,可以断开您的 GUI 层与数据库的连接,并促进您的应用程序的完整逻辑分区。拥有一个良好分区的应用程序将为将来代码迁移到其他 GUI 平台开辟道路。

我们现在可以完成概念图,如图 5 所示,以显示 GUI 和数据逻辑层之间的关系。

Yakov-fig-5_0.jpg

© . All rights reserved.