【1】场景
有一些领域数据置身于GUI控件中,而业务处理函数需要访问这些数据。
将该数据复制到一个业务对象中。建立一个Observe模式,用以同步业务对象和GUI对象内的重复数据。
【2】动机
一个分层良好的系统,应该将处理用户界面(GUI)和处理业务逻辑(Business Logic)的代码分开。之所以这样做,原因有以下几点:
(1) 你可能需要使用若干个不同的用户界面来表现相同的业务逻辑。如果同时承担两种责任,用户界面会变得过分复杂。
(2) 与GUI隔离之后,业务类的维护和演化都会更容易;你甚至可以让不同的开发者负责不同部分的开发。
尽管你可以轻松地将「行为」划分到不同部位,「数据」却往往不能如此。同一笔数据有可能既需要内嵌于GUI控件,也需要保存于业务模型里。
自从MVC(Model-View-Controller)模式出现后,用户界面框架都使用多层系统(Multitiered System)来提供某种机制,使你不但可以提供这类数据,并保持它们同步(sync)。
如果你遇到的代码是以双层(Two-tiered)方式开发,业务逻辑(Business Logic)被内嵌于用户界面(UI)之中,你就有必要将行为分离出来。
其中的主要工作就是函数的分解和搬移。但数据就不同了:不能仅仅只是移动数据,你必须将它复制到新建模块中,并提供相应的同步机制。
【3】做法
1、修改展现类(presentation class),使其成为业务类(domain class)的Observer[GoF]。
1.1 如果尚未有业务类(domain class),就建立一个。
1.2 如果没有从展现类(presentation class)到(domain class)的关联性(link),就将业务类(domain class)保存于展现类(presentation class)的一个值域中。
2、针对GUI class内的业务数据(domain data),使用自封装字段(Self Encapsulate Field(171))。
3、编译,测试。
4、在事件处理函数(event handler)中加上对设值函数(setter)的调用,以[直接访问方式]更新GUI组件。
在事件处理函数中放一个设值函数(setter),利用它将GUI组件更新为业务数据(domain data)的当前值。
当然,这其实没有必要,你只不过是拿它的值设定它自己。但是这样使用setter,便是允许其中的任何动作得以于日后被执行起来,这是这一步骤的意义所在。
进行这个改变时,对于组件,不要使用取值函数(getter),应该采取[直接取用]方式,因为稍后我们将修改取值函数(getter),使其从业务对象domain object(而非GUI组件)取值。
设值函数(setter)也将遭受类似修改。
确保测试代码能够触发新添加的事件处理(event handling)机制。
5、编译,测试。
6、在业务类(domain class)中定义数据及其相关访问函数(accessors)。
确保业务类(domain class)中的设值函数(setter)能够触发Observer模式的通报机制(notify mechanism)。
对于被观察(被监视)的数据,在业务类(domain class)中使用[与展现类(presentation class)所用的相同型别](通常是字符串)来保存。后续重构中你可以自由改变这个数据型别。
7、修改展现类(presentation class)中的访问函数(accessors),将它们的操作对象改为业务对象(domain object)(而非GUI组件)。
8、修改observer的update(),使其从相应的业务对象(domain object)中将所需数据拷贝给GUI组件。 (不要使用setter函数)。
9、编译,测试。
【4】范例
暂无
Good Good Study, Day Day Up.
顺序 选择 循环 总结