系统程序员成长计划-分离用户界面与内部实现(一)


       用户界面就是与用户交互的接口,通常包括输入和输出(显示)两个部分。用户使用键盘等输入设备把数据输入给程序,程序做相应处理后,输出结果到显示器或其它设备上。所谓的内部实现(也称为内部逻辑)就是负责数据处理的这一部分功能,它占的比例最大,其实现也最复杂。

分离用户界面与内部实现有很多好处:

1.用户界面与内部实现是相对独立的功能,从分而治之的思想来说,这可以降低系统的复杂度。

2.用户界面是多变的,而内部实现相对稳定。分离用户界面与内部实现可以让用户界面独立变化,使得用户界面的变化对内部实现的影响最小,从而降低系统整体的工作量。

3. 分离用户界面与内部实现有利于实施自动测试。带用户界面的程序难以自动测试,实现自动输入倒是不难,通常可以先录制所有的输入事件(如按键事件和点击事件),然后通过重放这些事件来做到自动输入。但是对输出结果的检查就很难自动进行了,如果根本不能检查测试的结果,自动测试的意义就不大了,最多只能当作压力测试而已。虽然有些商业工具能部分解决这个问题,但始终都不是正道。

4.有利于提高程序的可移植性。用户界面,特别是图形用户界面(GUI),在不同操作系统上有不同的实现,在同一个操作系统上也可能有多种不同实现。这些GUI的接口差别很大,如果内部实现与用户界面耦合太紧,则会影响程序的可移性。虽然有不少跨平台的GUI,像QT和GTK等,但是效果并不理想(我用GTK+写过一个在Linux和Windows运行的下载工具,当时遇到不少问题)。

对于传统的批处理程序,数据输入只在程序开始进行,整个处理过程没有用户的参与,分离它的用户界面和内部实现比较容易,只需要把内部实现提取为独立的模块,对外提供一个简单的接口就行了。

但是对于图形用户界面(GUI),整个过程都是由用户事件驱动的,用户有输入,程序就处理,并反馈结果给用户。这时分离用户界面和内部实现要困难一些,最简单的做法就是把每个事件的处理当作一个小的批处理,把它们提取成独立的模块或函数。

但这样做还是不够,内部实现有时反过来要调用用户界面的函数。比如一个下载软件,下载这个过程负责网络协议的处理,它可以认为是内部实现,由用户界面来调用。但是,在下载的过程中,它可能反过来要更新用户界面(比如显示当前的进度信息),这时要调用用户界面的函数。这种内部实现和用户界面之间的相互调用,需要一些更高级的方法才能解开它们之间的耦合。

本章将介绍一些分离用户界面和内部实现的方法。