APP下载

观察者模式在面向抽象编程中的应用

2016-09-10刘凌云

计算机与数字工程 2016年8期
关键词:设计模式观察者代码

刘凌云

(东北石油大学计算机与信息技术学院 大庆 163000)



观察者模式在面向抽象编程中的应用

刘凌云

(东北石油大学计算机与信息技术学院大庆163000)

为了提高软件系统的可扩展性和可维护性,在系统设计时必须搭建一个可以适应用户需求变化的系统框架,因此,在处理系统中对象间一对多的依赖关系时,采用面向抽象的思维方式,引入观察者模式,把变化部分从那些不变部分里分离出来,形成抽象类或接口,这样,当用户需求发生变化时,只需增添抽象类或接口的实现类,而无需改变原来的代码,从而提高了系统的稳健性,大大降低了软件系统维护的成本。实践证明,在项目设计中,具体抽象到哪一层可以结合各个开发平台的特性而做调整和优化,并不是一成不变的。

面向抽象编程; 观察者模式; 抽象类; 接口; 事件; 委托

Class NumberTP311

1 引言

在软件的开发过程中,虽然会拿出大量的时间来做需求分析,但是,用户的需求不可能一成不变,既然无法控制变化,那么可以根据特定的场景,采用适当的设计模式,把变化部分从那些不变部分里分离出来,形成抽象层,这样当用户需求发生变化时,就可以尽量地扩展原有的代码,而减少对已有代码的更改,来提高系统的可扩展性和可维护性。

2 面向抽象编程

所谓面向抽象编程,是指当设计一个类时,不让该类面向具体的类,而是面向抽象类或接口,即所设计类中的重要数据是抽象类或接口声明的变量,而不是具体类声明的变量[1]。

面向抽象编程是附属于面向对象思想体系,属于其一部分。或者说,它是面向对象编程体系中的思想精髓之一,面向抽象编程可以更好地实现面向对象要遵循的五大指导原则:单一职责原则:每一个类应该专注于做一件事情;开闭原则:每一个类应该是对扩展开放,对修改关闭;里氏代换原则:避免造成派生类的方法非法或退化,一个基类的用户应当不需要知道这个派生类;依赖倒转原则:用依赖于接口和抽象类来替代依赖容易变化的具体类;接口隔离原则:应当为客户提供尽可能小的接口,而不是提供大的接口[2]。

3 抽象类和接口

抽象类和接口都是对业务逻辑的一种抽象,业务具体实现通过该接口或抽象类的实现类来完成,它们是对客户端的一种承诺,是相对不变的[3]。当需求发生变化时,只需实现接口或者继承抽象类就可以扩展新的功能。同时由于接口或者抽象类没有变化,因此依赖于该接口的客户端类代码不需要进行改变。这就很好地做到了对扩展开放、对修改关闭,减少对系统的影响。

抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象[4];使用抽象类是为了代码的复用,它和子类之间是一般和特殊的关系;而接口是设计时对外部设定的“契约”,体现了自然界“如果你是……则必须能……”的理念[5]。使用接口可以实现多态,接口是它的子类应该实现的一组规则。

4 观察者模式

4.1问题描述

某单位开发一套航空订票系统,有如下场景:在系统收到顾客订票支付现金的消息后,要马上进行数据库记录、系统日志记录。

对该场景进行分析,对按照面向对象的思想,该场景里有顾客、订单、数据库三个类:类图如图1所示。

图1 订单支付类图

在该类图设计中,对于用户的上述场景我们完全可以满足。但是随着系统的运行,要考虑到该场景可能加入其他的记录操作或者通知操作:在系统收到顾客订票支付现金的消息后,除了要马上对数据库操作外,可能还要添加发送信息通知用户,购票送积分等其他记录操作;能触发用户更改数据的操作,除了订单被支付外,可能还会有别的通知操作(比如用户改签、飞机晚点)。

如果需求真的如上述所说那样变更,就得更改代码:就要增加一个SMSOperator类,该类里应该有一个sendMessage()方法,这样,就得修改Order类,再加一个List〈SMSOperator〉的变量,以及相关的添加取消方法,如果还有送积分操作,还得继续修改,这样,每添加一个记录操作,就得修改类中代码,这不符合开闭原则,为什么会导致这样呢?

因为在这样的设计中,Order类和DBRecorder类是双向耦合的关系,也就是说Order类中有DBRecorder类的实例,同样DBRecorderOrder类中有Order类的实例;这样设计的缺点就是:不论修改哪个类中的代码,另一个类中的代码都有可能要发生改变:比如就要在把Order类重命名是FlightOder,就得更改DBRecorder中的代码,同样,如果把DBRecorder的updateData()方法重命名,同样要更改Order中的代码;不仅如此,客户端也依赖具体的Order类和DBRecoder类,这样再更改的Order类和DBRecoder类的时候,同样也需要更改客户端的代码;也就是说,这样的设计模式并不能满足需求的变化,对后期的维护非常不利。在这个设计的基础上,既然通知操作和记录操作都有可能发生变化,那么应该把这些变化抽象出来,形成抽象类或者是接口,形成观察者模式。

4.2观察者模式定义

观察者模式定义了对象间一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象[5]。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己[6]。

图2 观察者模式类图

在该模式中,通过对多个通知操作和记录操作的实例进行抽象,制定好规范和契约,形成抽象类和接口,抽象类或接口只负责定义属性和操作,把具体怎样实现操作交给它们的实现类去完成。从类之间的关系上来说,客户端依赖于抽象,具体的实现类也依赖于抽象。依赖于抽象的优点就是即使实现类不断变动,只要抽象不变,客户程序就不需要变化,这大大降低了客户程序与实现细节的耦合度[7],观察者模式类图如图2所示。

将上述问题场景按照观察者模式进行修改,为购票对象添加纪录观察者:数据库观察者,短信观察者。

1) 抽象主题

定义一个抽象类ATicketSubject,规定具体主题需要继承的三个抽象方法,用来添加、删除观察者及通知观察者更新数据。主题接口ITicketObservable代码如下:

public abstract class ATicketSubject{

private IList〈ITicketObserver〉 observers = new List〈ITicketObserver〉();

public void ResisterObserver(ITicketObserver o){

observers. Add (o) };

public void UnResisterObserver(ITicketObserver o) {

observers. Remove(o) };

public void notifyObserver(){

foreach (ITicketObserver o in observers) {o.Update();}}

2) 抽象观察者

设计观察者ITicketObserver接口:代码如下:

public interface ITicketObserver {

public void Update(); }

3) 具体主题FlightOrder

具体主题类FlightOrder的部分代码如下:

Public class FlightOrder: ATicketSubject {

private string orderState; //得到当前用户是否支付订单}

4) 具体观察者

在本问题中,购票之后的操作为具体观察者;创建的具体观察者类分别为:SMSOperator和DBRecorder。SMSOperator部分代码如下:

Public class SMSOperator implements ITicketObserver {

private string observerState;

private ATicketSubject subject;

public SMSOperator (ATicketSubject subject) {

this.subject = subject;}

Public void update(){

observerState = subject.SubjectState;

if(observerState =”订单已支付”){

sendMessage(); //发送短信给用户}

}

具体观察者DBRecorder的代码同具体观察者SMSOperator。

从上述代码中可以看出,观察者模式体现了松耦合的设计原则:即当Subject类中的数据有更改时,会调用notifyObserver函数,来通知所有的观察者更新数据,即调用Observer中的Update方法,但是Update只是在观察者中更新了数据,但是这些数据具体如何应用就看观察者自己的了。在订单完成支付时,购票系统会通知数据观察者更新记录数据,短信观察者给用户发短信。但这一切的动作都与主题和Update无关了。从而在遵循观察者模式最小的接口的规则下,观察者怎么改变(即再实现其他动作接口,继承其他超类),都不会影响主题类。而主题类的具体实现者(ConcreteSubject)中无论扩展什么样的行为,也不会影响观察者(Observer)。

4.3观察者模式优缺点

观察者模式在被观察者和观察者之间建立起松耦合关系这种“针对抽象编程”的做法体现了面向对象设计复用原则中的“依赖倒转原则”,可以有效减少模块间的“紧耦合”,有利于提高系统的可维护性和扩展性[8]。

但是从上述代码中可以看出,依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。在多个具体观察者中,并不是所有的观察者都执行相同的Update方法[9],也就是说SMSOperator类中的sendMessage()方法和DBRecorder中的updateData()方法关注的目标中的状态是相同的,但具体观察者所执行的操作却是截然不同的[10],把它们统一抽象为Update(),这和现实世界中的命名是矛盾的。

4.4基于为事件委托的观察者模式

要想消除上述依赖关系,“.NET”框架中的委托机制恰恰具备这个特征:委托并不知道也不关心它引用的方法所属的类,只要方法的签名与委托的签名相匹配,该方法就可以被调用[11]。“.NET”框架还提供了事件(event)机制。事件是建立在委托机制上的,包含了事件成员的对象在某些特定事情发生时可通知其他对象[12]。

通过在目标对象中定义一组事件和委托,将具题观察者中的Update()方法作为委托对象与目标对象的事件绑定来实现通知更新的服务。一方面,目标发送通知时,利用委托允许同时被委托者增加多个对象这一“多播”的特性,来实现注册观察者[13],在执行Notify()方法时,无需指定观察者,通知会自动传播。另一方面,观察者自己决定是否需要接受通知[14]。利用ASP.NET中页面回传的事件处理机制,来达到观察者注销的效果[15],基于事件机制的观察者模式如图3所示。

图3 基于事件的观察者模式

图3中可以看出,通过在具体目标类中声明事件,在客户端程序中关联和引发事件,降低了了Observer和Subject的耦合度,具体观察者只依赖于Subject。要引入新的通知操作,只需要在具体观察者的更新方法与具体主题中的相关事件关联即可。相关代码如下

1) 具体目标类FlightOrder代码如下:

public class FlightOrder: Subject

{

private string orderState;

public delegate void EventHandler () ; / / 声明委托类型及签名

public event EventHandler Update; / / 声明事件 Update

public void Notify()

{

Update() ;}}

2) DBRecorder(具体观察者ConcreteObserver1)

public class DBRecorder

{

public void updateData (){}

}

3) SMSOperator(具体观察者ConcreteObserver2)

public class SMSOperator

{

public void sendMessage(){}

}

4) 客户端

FlightOrder fo= new FlightOrder () ; / /定义具有目标对象

/ / 定义 2 个具体的观察者

DBRecoder db= new DBRecoder(“我是数据库观察者”,fo)

SMSOperator sms= new SMSOperator( “我是信息观察者”,fo)

/ / 将方法updateData 和sendMessage和事件 Update关联

fo.Update + = new EventHandler (db.updateData) ;

fo.Update + = new EventHandler (sms.sendMessage) ;

fo. orderState =“订单已经支付”;

fo.Notify ();/ Update 事件,分别调用方法 updateData 和 sendMessage

5 结语

观察者模式是解决软件设计中对象间一对多依赖关系的高效和成熟的设计模板,在软件系统开发中被广泛应用。国外在研究设计模式的同时,也在相对应的研究反模式。反模式其实也是一种模式,不过它主要考察的是这种模式所带来的不良后果。用面向抽象设计原则指导分析与解决问题,通过发现可能变化的结构,用面向抽象的方法对其进行封装与隐藏,所取得的效果可能与采用设计模式一致甚至更优[16]。

[1] ROBERT C MARTIN. Design Principles and Design Patterns[EB/OL]. http://www.objectmentor.com,2008-08-03.

[2] 李航.基于MDA的BSS计费系统设计与实现[D].哈尔滨:哈尔滨工业大学,2012:24.

LI Hang. MDA-based BSS billing system design and implementation[D]. Harbin: Harbin Institute of Technology,2012:24.

[3] 耿祥义,张跃平.Java设计模式[M].北京:清华大学出版社,2009:132-134.

GENG Xiangyi, ZHANG Yueping. Java design pattern[M]. Beijing: Tsinghua University Press,2009:132-134.

[4] 曹步清,金瓯.Java中的Abstract Class与Interface技术研究[J].计算机技术与发展,2006,8:109.

CAO Buqing, JIN Ou. In Java Abstract Class and Interface technology research[J]. Computer Technology and Development,2006,8:109.

[5] 孟婷婷,何利力.Observer设计模式在手机导航软件中的应用[J].电脑知识与技术,2014,7:5.

MENG Tingting, HE Lili. The Observer design pattern in the application of mobile navigation software[J]. Computer Knowledge and Technology,2014,7:5.

[6] Erich Gamma, Richard Helm, Ralph Johnson.设计模式:可复用面向对象软件的基础[M].李英军,马晓星,蔡敏等,译.北京:机械工业出版社,2005:89.

Erich Gamma, Richard Helm, Ralph Johnson. Design patterns: elements of reusable object-oriented software[M]. LI Yingjun, MA Xiaoxing, CAI Min, et al. Beijing: The Basis of Mechanical Industry Publishing House,2005:89.

[7] kongls08.设计模式六大原则(3):依赖倒置原则[EB/OL]. http://blog.csdn.net/kongls08/article/details/6365833.

kongls08. Design pattern six principles (3): dependency inversion principle[EB/OL]. http://blog.csdn.net/kongls08/article/details/6365833.

[8] 欧阳宏基,杨卫忠,赵蔷.观察者模式在Java事件处理中的应用研究[J].微处理机,2013.4:77.

OUYANG HongJi, YANG Weizhong, ZHAO Qiang. The observer pattern in Java event processing application[J]. Journal of Microprocessor,2013,4:77.

[9] 张宁,王越,王东.观察者模式及其在软件开发中的应用[J].大众科技,2008,11:10.

ZHANG Ning, WANG Yue, WANG Dong. The observer pattern and its application in software development[J]. Journal of Popular Science and Technology,2008,11:10.

[10] 吴清寿.基于事件机制的观察者模式及应用[J].重庆理工大学学报,2012,26(9):102-103.

WU Qingshou. The observer pattern based on event mechanism and application[J]. Journal of Chongqing University of Science and Technology,2012,26(9):102-103.

[11] Entrusted tutor[EB/OL]. http://msdn.miscrosoft.com/library /chs/defaul.asp?url =/library /CHS/csref/html/vew lkdelegatestutorial.asp.

[12] 微软公司.基于C#的.NET Framework程序设计[M].北京:高等教育出版社,2004:149.

Microsoft. Based on the C#. NET Framework programming[M]. Beijing: Higher Education Press,2004:149.

[13] 吴清寿.基于事件机制的观察者模式及应用[J].重庆理工大学学报,2012,26(9):101-102.

WU Qingshou. The observer pattern based on event mechanism and application[J]. Journal of Chongqing University of Science and Technology,2012,26(9):101-102.

[14] 冯新扬,沈建京,姚松林.基于ASP.NET的观察者模式应用研究[J].计算机应用与软件,2008:173-1741.

FENG Xinyang, SHEN Jianjing, YAO Songlin. Based on the observer pattern of ASP.NET application study[J]. Journal of Computer Applications and Software,2008:173-1741.

[15] 周永麒.数字校园的中学信息化平台的设计与实现[D].上海:交通大学,2012,7:12.

ZHOU Yonglin. The design and implementation of high school information platform of digital campus[D]. Shanghai Jiaotong University,2012,7:12.

[16] 延开,定海.面向对象分析和设计[M].北京:清华大学出版社,2001:105.

YAN Kai, DING Hai. Object-oriented analysis and design[J]. Beijing: Tsinghua University Press,2001:105.

Application of the Observer Mode in Abstract-Oriented Programming

LIU Lingyun

(College of Computer and Information Technology, Northeast Petroleum University, Daqing163000)

In order to improve scalability and maintainability os software system, a system framework must be able to build to adapt to the changing needs of the user is system design, therefore, in dealing with one to many dependencies in the system, abstract oriented way of thinking is used, the observer mode is introduced, the change part is separated from unchange part, an abstract class or interface is formed, so that when an user needs change, an abstract class or interface implementation class is added without changing the original code, thereby the robustness of the system is improved greatly the cost of software maintenance is reduced. Practice has proved that in project design, which layer is abstracted specifically can combine various development platforms and make adjustments and optimization, it is not immutable.

abstract-oriented programming, observer mode, abstract, interface, event, delegate

2016年2月7日,

2016年3月30日

刘凌云,女,硕士,研究方向:软件工程。

TP311

10.3969/j.issn.1672-9722.2016.08.017

猜你喜欢

设计模式观察者代码
“1+1”作业设计模式的实践探索
三维协同设计模式下的航天项目管理实践与展望
冷静而又理性的观察者——德国华人作家刘瑛访谈
交通机电工程设计模式创新探讨
创世代码
创世代码
创世代码
创世代码
互动式设计模式研究
观察者模式在Java 事件处理中的应用研究*