《设计模式在lwgui的研究实现》由会员分享,可在线阅读,更多相关《设计模式在lwgui的研究实现(12页珍藏版)》请在金锄头文库上搜索。
1、设计模式课程论文题 目: 设计模式在 LWGUI 的实现研究 姓 名: 学 号: 专 业: 班 级: 导 师: 1摘要:设计模式的主要作用是适应变化的需求,其灵活性可以使设计方案更容易扩展和复用。在系统设计中,应尽量使用成熟的设计模式来优化设计模型的局部设计。本文以一个轻量级的跨平台的图形用户界面的框架系统(Light Weight GUI,LWGUI)为例,详细介绍了观察者模式和外观模式这两种模式在 LWGUI 系统中的应用实现。关键词:设计模式;扩展;复用;观察者模式;外观模式1 引 言软件复用是软件开发人员的不懈追求,它能够提高软件生产率以及软件质量。针对软件复用,我们采用设计模式来记录
2、软件设计知识,这可以使软件复用从代码复用提高到软件开发各阶段知识的复用。设计模式是可复用面向对象软件的基础,它以系统化和规格化的方式记录了可重复使用的软件设计方案和经验。它区分、命名并且抽象了面向对象设计中的通用概念。设计模式通过明确对象、对象间的协作和职责分配,捕捉到了隐藏在设计背后的意图。2 设计模式2.1 观察者模式 (1) 设计意图 观察者模式的设计意图包括: 1) 定义对象之间多对一的依赖关系,也即多个对象依赖于一个对象的关系,同时保证,当被依赖的对象状态发生变化时,所有的依赖者会被自动地通知。观察者模式的另一个名称“出版订阅模式”很好地说明了这个设计意图:被依赖的对象向外发布自己的
3、状态,而此前订阅了该状态的所有对象都会得到通知,这其实类似于一种消息在对象间的广播。 2) 当一个对象需要通知另外一个对象,而又无法预知哪些对象将被通知,通过观察者模式就可以减弱通知对象和被通知对象之间的耦合关系。 3) 当一个模块(模块 A)的变化需要另一个模块(模块 B)做出相应的修改,而又不知道有多少个类会被修改时,使用观察者模式就可以切断这种依赖关系,即模块 A 的变化不再影响模块 B,模块 B 也无需做任何修改。换句话说,这时,模块 B 对模块 A 的依赖关系由直接依赖转变为间接依赖,具体的依赖关系是由模块 A 动态设定的。因此,两个模块可以在互不干扰的情况系下,相对独立地被复用和修
4、改。 2(2) 基本结构 图 2-1 为观察者模式的结构图。在结构图中,有如下一些类,它们共同完成观察者模式的各项职责。 1) 主体(Subject)类:即被观察者类的基类,它管理所有的观察者,并提供添加和删除观察者的方法,观察者的数量一般不受限制。 2) 观察者(Observer)类:定义一个通知接口来接受主体类发来的通知消息。 3) 具体的主体(ConcreateSubject)类:即具体的被观察者类,它针对不同的需求,实现具体的主体属性和方法,决定何时发送通知消息等。 4) 具体的观察者 (ConcreateObserver)类:针对不同的需求,实现具体的通知接口,以接收具体的主体类发来
5、的通知消息,并可以根据需要对消息进行特定的处理。 图 2-1 观察者模式结构图2.2 外观模式 (1) 设计意图 外观模式可以为一个子系统中的多个类提供统一的接口。外观模式定义了一个高层次的接口,并使一个子系统更易于使用。 (2) 基本结构 图 2-2 为外观模式的结构图。 3图 2-2 外观模式结构图图 2-2 中,子系统的接口不一定是具体的外观类,它和外观类之间的关系可能会有两种: 1) 子系统的接口是一个抽象类,不包含任何属性和具体实现,其中定义的所有的接口函数都是纯虚函数;而外观类是该抽象类的派生类,隐藏在子系统中。在这种实现方式中,客户程序所看到的只是一个纯粹的接口,而具体的实现都被
6、外观类封装到了子系统内部。 2) 子系统的接口就是外观类的头文件(对 C+语言而言) ,客户程序可能会看到一些外观类的私有属性和私有方法。 显然,第一种方法比较纯粹,比较理论,而且,在第一种方法里,如果子系统的接口可以被多个子系统共用,它就会有多个不同的派生类,这在某些情况下非常有用。如果子系统的接口只有一个派生类,即该子系统的外观类,可以使用第二种方法,因为它比较简单和直接。 外观类一般应以单件类(Singleton)的形式出现,这样,客户程序就可以通过单件类的静态方法获得子系统的惟一接口实例。另外,外观类一般要负责创建和销毁子系统中的其它相关对象,管理其它对象的生命周期。当客户程序调用外观
7、类中的接口函数时,外观类必须知道每一个特定的请求应该发送给子4系统中的哪个类或对象,或者,应该让子系统中哪些类共同处理。 3 观察者模式在 LWGUI 系统中的应用实现根据对 LWGUI 系统的架构分析可知,在框架层和操作系统适配器层中,有几个类和消息传递相关,即操作系统适配器会在适当的时候,发送消息给应用程序、屏幕、定时器管理器这三个类。但随着系统不但的扩展,消息的接收者数量,处理方式等都有可能在未来发生变化。在没有引入观察者模式前,系统的结构图如图 3-1 所示。 图 3-1 未引入观察者模式时的消息传递方案LWG_OSAdaptor 的派生类负责各具体操作系统的程序启动、主窗口创建、消息
8、接收等工作。程序启动后,对于 VxWork 等操作系统,该派生类可以通过一个循环不断查询各种操作系统消息(如键盘、鼠标、时钟、网络、串口等消息) ,对于 Windows 或 Linux 等操作系统,可以在相应的派生类中实现一个窗5口函数,以接受各种系统消息。 当操作系统适配器类接收到系统消息后,它需要根据系统消息的类型,把消息发送给不同的对象,例如,键盘、鼠标消息发送给屏幕类的对象实例,启动消息发送给应用程序类的对象实例,时钟消息发送给定时器管理器类的对象实例等等。显然,此处的每一个消息都只是发给一个对象,并不会发送给多个观察者,不存在一对多的依赖关系。 但随着消息类型的不断增多,接受消息的控
9、制类在未来也可能会发生变化,而这种变化正好是观察者模式试图解决的问题。而且,操作系统适配器层要移植到不同的操作系统上,实际上存在多个不同的操作系统适配器层实例,所以,框架层的变化应尽可能少地影响操作系统适配器层,否则,系统的扩展性和复用性就无从谈起,这同样符合观察者模式的设计意图。因此,尽管这里不存在一对多的依赖关系,但为了达到减少层与层之间的耦合、把直接依赖变成间接依赖的目的,观察者模式仍可发挥很大的作用。只是在具体实现上,LWGUI 中的观察者模式和标准的 GoF 的观察者模式略有不同。 观察者模式的实现方法如下:在 LWGUI 中,首先实现了一个 Observer 类,该类是一个抽象类,
10、其中的 OSMessage()接口可用于接收操作系统消息,相当于观察者模式中的 Update()方法。由于该类会同时被框架层和操作系统适配器层使用,应把它放在独立的应用包中。Observer 类的代码如下所示。 class LWG_OSMsgObserver public: virtual LWG_OSMsgObserver() virtual void OSMessage(LWG_Message * pMsg) = 0; ; 框架层的屏幕、应用程序、定时器管理器等类都是从LWG_OSMsgObserver 类中继承出来的,这样它们都具有接收操作系统消息的能力。负责转发操作系统消息的类是操作系
11、统适配器层的适配器类LWG_OSAdaptor,但是,由于每种特定类型的消息不是发送给所有的观察者,而是发送给某一个注册了该类型消息的接收者,因此,记录观察者的方式和标准的观察者模式略有不同。 先定义消息类型的枚举结构: enum LWG_MSG_TYPE 6 LWG_MSG_STARTUP, /系统启动消息 LWG_MSG_HALT, /系统停止消息 LWG_MSG_DRAW, /屏幕刷新或窗口元素重画消息 LWG_MSG_KEY, /键盘消息 LWG_MSG_MOUSE, /鼠标消息 LWG_MSG_TIMER, /定时器消息 /以上为所有的系统消息 /系统内部使用,不是一个消息类型,表示
12、最大的系统消息个数, /之前为所有的系统消息,之后为内部消息 LWG_MAX_SYS_MSG, /请求重画消息,控件需要重画时向窗口发送此消息,/窗口需要重画时向屏幕发送此消息,/由屏幕根据该窗口是否是焦点窗口来决定如何重画LWG_MSG_DRAW_REQUEST,LWG_MSG_FOCUS, /焦点切换消息LWG_MSG_NOTIFY, /通知消息LWG_MSG_UPDATE_VIEW / MVC 模式的视图更新消息;对于每一类系统消息,需要记录一个接收该消息的观察者,而且,在 LWGUI 系统中,每一类消息只能有一个观察者(当然,同一个观察者可以观察多个类消息) ,因此,只需在 LWG_O
13、SAdaptor 类中定义一个大小为LWG_MAX_SYS_MSG 的数组,用该数组来保存每个消息类型对应的观察者对象指针即可。观察者注册时,需要提供它想注册的消息类型,然后该观察者的指针就会被记录在数组的相应位置。当然,注册的前提是该观察者类实现了LWG_OSMsgObserver 接口。当 LWG_OSAdaptor 类接收到系统消息时,只要从数组中查询出该系统消息对应的观察者对象指针,然后调用该指针的 OSMessage()方法,就可以把消息发送给观察者来。LWG_OSAdaptor 类和观察者模式的相关代码如下:class LWG_OSAdaptorpublic:/* 注册系统消息的观
14、察者* 每个系统消息只能有一个观察者(即消息接受者,LWG_OSMsgObserver 的子类)* type 系统消息类型* pObserver 注册的系统消息的观察者指针* 该消息以前设置的观察者指针7*/LWG_OSMsgObserver * SetMsgObserver(const WORD type, LWG_OSMsgObserver * constpObserver);/* 发送系统消息给注册的观察者* pMsg 指向要发送的系统消息,由于是同步消息,发送者必须负责分配和释放该消息*/void SendMsg(LWG_Message * pMsg);protected:/ 记录所有
15、的系统消息的观察者的数组LWG_OSMsgObserver * m_ppObserverLWG_MAX_SYS_MSG; ; LWG_OSMsgObserver * LWG_OSAdaptor:SetMsgObserver(const WORD type, LWG_OSMsgObserver * const pObserver) LWG_OSMsgObserver * tmp = m_ppObservertype; m_ppObservertype = pObserver; return tmp; void LWG_OSAdaptor:SendMsg(LWG_Message * pMsg) if(pMsg-wTypewType) m_ppObserverpMsg-wType-OSMessage