GUI装配器的模式

时间:2022-10-10 07:26:14

GUI装配器的模式

摘要:本文提出了一种界面设计中的架构模式-界面装配器模式,它致力于分解界面,将界面和组装行为解耦,将界面逻辑处理与后台业务逻辑处理解耦,这样我们在开发GUI胖客户端界面应用时可以从众多的界面控制管理中解脱出来,而专注于我们的后台业务逻辑的开发。通过该模式,我们可以动态地组装我们的界面,我们甚至还可以在我们的界面中轻松地插入 transaction 事务或 session 会话管理。

关键词:界面;装配;解耦;模式

中图分类号:TP312文献标识码:A文章编号:1009-3044(2008)17-21433-02

1 引言

界面设计常常是模式产生的根源,无论是架构模式,还是设计模式,比如 MVC 模式,Observer,Facade 等,也是整个软件行业向前发展的动力。遗憾的是,即使在软件技术发达的今天,界面设计仍是软件设计中的难以突破的瓶颈之一,要将界面进行分解是很困难的,它不像我们的业务逻辑,可以方便地按职责分解到不同的类中去实现,一般的做法只能是在界面元素的事件触发(比如按钮点击事件)时,将输入数据封装成一个数据对象传给后台的逻辑处理类来处理。在这里我会从一个简单的设计模型开始,一步步走向一个完整的架构。借此也向大家展示一个架构设计的思维历程。

2 界面部件装配

当我们的装配逻辑很简单时,我们可以定义一个 assemble() 方法来负责装配行为。但是当我们的界面需要组装一系列 EditorComposite 时,就会牵涉到选择逻辑,选择逻辑不一定很复杂,但我们还是应该把这种行为从 Editor 中分离出来,这样 Editor 可以集中精力负责与用户交互方面的职责,而装配行为被分配到一个新的类 EditorAssembler 中,这样做还有一个好处,就是我们一旦有新的 EditorComposite 需要添加时,我们只需要改变 EditorAssembler 的代码,而不用修改 Editor 的代码,这就把变化隔离出来,对 Editor 的修改关闭,对装配行为的扩展开放。这正是面向对象设计领域反复强调的基本原则-开放-封闭原则(Open-Close Principle)。架构如下图所示:

EditorAssembler:该类处理 EditorComposite 的创建,还包括多个 EditorComposite 的选择逻辑。这里的选择逻辑我们可以用 if/else 或 switch/case 来硬编码,如果逻辑不是很复杂而且今后的修改不会太频繁的话,用这种方法就足够了,当然可以考虑将多个 EditorComposite 的装载信息专门用一个资源/信息类来存储,这在 EditorComposite 比较多的情况下很有效,这样每次添加 EditorComposite 就只需要改变这个资源类,这是一个很有用的建模原则(为了简化我们的核心模型,我在这里不将这个资源类表示出来)。

3 IO 数据流组装

在一个标准的界面程序中,我们首先会有一组输出数据,比如按”确认”按钮之后,我们需要将界面元素上的输入信息输出到后台逻辑类来处理或直接调用好几个逻辑类分别处理不同的界面元素输入信息了。我们一般习惯上可能直接将这个数据传递到逻辑类来处理。这样做三个缺点:其一,如果我们的数据读写处理要求必须在特定的 context 中才能进行,这样的话我们不能在界面中直接调用后台逻辑处理类了,在一些涉及底层(比如协议层)的开发时,经常会碰到只能读不能写的情况。其二,UI 的可替代性差,假如我们今后需要一种方案可以在运行时可以替换不同的 UI 但输出的数据是一样的,也就是说后台逻辑处理完全一致,那么这种情况我们就需要每一个 UI 自己去调用后台逻辑类,重复编码,而且可能由于程序员的失误每一个 UI 用了一个逻辑类,从而导致一个完全相同行为的类有了好几个不一致实现版本,这样不仅严重违反了面向对象设计,而且还可能产生难以预料的 bug,难以维护。其三,UI 的可重用性差,对于上面多个 UI 对应一种逻辑处理的例子,由于 UI 依赖了后台逻辑类,如果今后要修改逻辑类结构的话,我们就需要修改每一个 UI。如果我们还有一种需求是要支持一个 UI 在不同的环境下需要不同的后台逻辑类时,我们可能要专门在一个 UI 中设置一个属性来标识后台将要使用的逻辑类,这会很复杂。

解决上面几个缺点只有一种方法,就是将后台逻辑类与 UI 解耦。如果我们把要处理的输出数据打包成一个输出数据对象从界面统一输出,再由 UI 的调用者决定调用哪一个后台逻辑类来处理数据,而不是 UI 自己决定调用行为,我们调用 UI 时,可能某些界面元素需要的从环境中动态装载数据,比如一个下列列表,还有一些我们上一次配置好的数据这次需要更新,也需要将已有数据导入。所以我们需要一个输入数据对象。这就得到如图2的模型:

InputDataObject:该类封装了输入数据。由 EditorComposite 负责解析这些数据。

OutputDataObject:该类封装了输出数据。由 EditorComposite 负责产生这些数据。

Editor 负责传输这两个数据对象。

从上面的模型我们可以看出 Editor 类其实相当于一个 Facade,所有的界面与用户的交互都由它负责集中调度管理,Editor 会将装配行为分配给 EditorAssembler 类来处理,它还负责临时存储输入输出数据,当然如果我们有类似 transaction 或 session 之类的处理会由 Editor 委派到别的相关类去处理。应用 Facade 设计模式,我们可以给 Editor 改个名字叫 EditorFacade,这样更能体现设计者的意图,千万不要忽视类的命名,设计是一门严肃的科学,每一个细节我们都不能苟且,对架构的设计更要严谨。命名可以起到沟通的作用,还能起到提醒的功能,EditorFacade 提醒我们以后要给它添加新的行为是记住它是一个 Facade,不能将不相干的职责分配进来。

4 结束语

本文所讲述的界面装配器模式为我们提供了将界面和组装行为解耦,将界面逻辑处理与领域逻辑处理解耦的价值观,在 GUI 胖客户端型界面中可以大量应用,当然,任何模式,不管是设计模式还是架构模式,都有它的适用性,只有合适的,没有绝对的优劣与好坏之分。

参考文献:

[1] GOF.Design Patterns:Elements of Reusable Object-Oriented software[M].机械工业出版社,2000:175-207.

[2] Martin Fowler.Patterns of Enterprise Application Architecture[M].机械工业出版社,2004:274-310.

[3] 阎宏.Java与模式[M].电子工业出版社,2002:471-490.

注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文

上一篇:独立学院学分制教学管理下的信息化平台构建 下一篇:基于SEP3203的U-Boot启动分析和移植