[理解实践PureMVC框架]1-框架简介及框架各个模块中的接口声明

框架的使用,无非就是为了代码的重用和解耦,使得工程易于理解、维护或重构等。

那PureMVC这个框架是如何达到这些目的的呢?我就以自己的理解简单讲下。我的理解肯定是学习了解别人的介绍后自己做出的总结,别人的介绍可能又是学习别人的理解来的。因此,我的理解可能和别人的差不多,然后会有点点自己的总结在里边。当然,我会在理解后,自己设计一些例子或写个代码进行演示,这样更助于理解。

其实学习了解别人的理解并不一定就会快,或比较省事,别人的理解毕竟是按他自己的情况理解的,每个人的情况不一样。但是我们可以通过学习多个人的理解,来总结出自己的理解。如果你没接触过一类事物,就算你看别人的理解,对于你来说也是一个新概念,别人的理解只是给你一种思路去如何学习。

传统的MVC框架中:Model层就是负责存放数据,它没有操作。View层只负责界面的显示逻辑。而Controller层呢,就是当Model层的数据发生改变后,获取到相关数据并计算好,然后更新View层相关的数据显示,其实它就相当于View层和Model层的一个沟通桥梁

比如有个游戏的主界面,它需要显示一些角色名、金币、经验等数据。然后按MVC的框架设计,我们把这些数据通通放到一个Model层,界面的元素和显示逻辑通通放到一个View层,操作数据和更新界面数据的逻辑通通放到Controller层。但是我们想一下,有些数据是所有界面共用的,像角色名,金币这些,可能不止这一个界面需要用到,如果我们为每个界面都单独写3个MVC层,那代码就重复了(没达到代码重用的理念)。当然我们可以在其它界面直接调用一个界面的MVC层,这样就不用重复写代码了,但是,这样还会有什么问题呢?不同的界面,它们之间可能有共用的数据,还会有特有的数据,如果我们在一个界面的MVC层直接调用另一个界面的MVC层的话,会导致耦合度变高(没实现解耦)。

因此,用传统MVC框架去写的话,如果一个界面越复杂,MVC层的代码就会越多,然后会变的越复杂,越难控制,界面与界面间的代码就会越耦合。而PureMVC框架,就是为了解决这一问题的。下面我再简单介绍下PureMVC中各个层的作用,当然,如果你喜欢更官方、最原始的说法,可以直接到官网看说明,官网也有介绍。如果你觉得官方的“太官方”了,可以看下我的,或其他人的。

PureMVC本质上还是一个MVC框架,它只是围绕MVC这3个层做了扩展,加入了一些设计模式,使得代码更方便重用和解耦。在PureMVC中,涉及到的设计模式有:命令模式、代理模式、中介模式、观察者模式、外观模式和单例模式(设计模式的使用我就不讲了)。

  • 通过命令模式,将Controller层的逻辑分解成一个个独立的小的命令,然后Controller层只负责保存这些命令的引用,而这些命令的执行是通过通知,也就是观察者模式来触发的,一个命令对应着一个通知,当收到通知时,对应的命令就会自动执行(不用我们手动调用)。通知和命令是通过映射关联起来的。可以在命令类里头注册中介类和代理类。命令自身也可以发送通知。
  • 通过代理模式,将Model层的数据分解成更独立的模块,然后Model层只负责保存这些代理的引用,外界通过数据的代理类来获取相应的数据。比如金币代理、经验代理等,其它地方就统一访问这个代理来获取数据了。当然也别分的太细,不然显得啰嗦。代理自身也可以发送通知。
  • 通过中介模式,将View层的界面元素跟相关逻辑分离出来,然后View层只负责保存这些中介的引用。View层还可以保存观察者类,一个观察者对应了一个通知需要执行的命令。如果一个界面太复杂的话,可以为其设置多个中介类来管理更新这个界面。中介类负责监听相关通知来更新界面的数据显示和其它界面逻辑。中介类可以获取并访问代理类。中介自身也可以发送通知。
  • 观察者模式是供MVC这3层之间交流的,这样它们之间就不用直接调用其它模块的方法了,而是通过通知,间接执行相关方法。从而达到模块间的解耦。当然,观察者模式用太多的话,调试起来会比直接调用的麻烦
  • 外观模式其实就是封装了MVC这3层的方法,它并没有实现额外的东西,这样做的目的是为了提供一个统一的方式给外界使用,而不用关心MVC这3层的具体实现。
  • 单例模式用的比较多,而且用起来比较方便。它是为类提供一个实例,这样我们在使用这个类的时候,不用担心是否实例化或会不会实例化多个。

各个层之间的关系差不多就是这样了。在使用PureMVC这个框架的过程中,我发现一个明显的缺点就是:它封装的太多了,以致于执行一个简单的步骤,都需要一层层的执行。

接下来看下各个模块的接口。其实ooc-lang中的接口并没有其它传统的OOP语言的好用,在实现框架的过程中并无多大作用,差不多就是用来声明给人看一下的,不过我还是用了接口,因为有个地方需要用到,也可以使代码结构跟官方的统一。至于ooc-lang的接口的缺点,可以找我另一篇介绍ooc-lang的文章了解。

接口相当与C语言中的头文件吧,它只提供声明,不提供实现,然后可以方便的作为参数类型,Java中还可以通过接口实现多继承等。

先讲INotifier.oocINotification.oocIObserver.ooc这三个模块吧,其它几个模块都需要继承或需要用到的。

/*
 *	INotifier.ooc
 *	INotifier类就是用来发送通知的,它不做其它事。其它类只需继承该类就可以发通知了
 */
 
import patterns/facade/Facade
import patterns/observer/Notification

// 虽然说了是接口啊,但是这里我把它定义为了一个抽象类,因为ooc-lang中的接口不太一样,也无法多继承
// 所以我用抽象类来解决这问题了
INotifier: abstract class {
	// 其实我感觉PureMVC这个框架的Notifier类不太合理,虽然我这里代码和原来的不完全一样,但整个过程是一样的
	// 发通知的过程是这样的:调用Facade这个单例中的发通知方法,而Facade中的方法又是调用
	// View中的方法来发通知的,最后才会通知到Observer那里
	// 这就导致,要这里能正确发通知的话,得确保View这个模块实现正确,然后Facade这个模块实现也正确,最后这里才正确
	// 所以我感觉这里耦合度还是挺高的
	facade: Facade {
		get {
			return Facade getInstance()
		}
	}

	// 这个方法的实现,是和官方的一样的
	// 参数分别是通知名,通知的消息体(需要传递的参数放这里),通知的类型
	sendNotification: func(notificationName: String, body: Pointer = null, type: String = null) {
		facade notifyObservers(Notification new(notificationName, body, type))
	}
}
/*
 *	INotification.ooc
 *	通知的接口
 */

// 一个通知包括通知名,通知的消息体和通知类型了
INotification: interface {
	getName: func -> String

	setBody: func(body: Pointer)

	getBody: func -> Pointer

	setType: func(type: String)

	getType: func -> String

	toString: func -> String
}
/*
 *	IObserver.ooc
 *	观察者接口
 */
 
import patterns/observer/Notification

// 一个观察者包含一个对应的执行方法,当收到通知时,就执行观察者里的方法
IObserver: interface {
	setNotifyMethod: func(notifyMethod: Func(/*Pointer, */Notification))

	setNotifyContext: func(notifyContext: Pointer)

	notifyObserver: func(notification: Notification)

	compareNotifyContext: func(object: Pointer) -> Bool
}

接下来就是命令接口了:

/*
 *	ICommand.ooc
 *	命令接口
 */
import patterns/observer/Notification
import interfaces/INotifier

// 这里我同样将它声明为了一个抽象类,我需要将它作为参数传给函数。原因还是因为ooc-lang中的接口问题导致的
// 命令当然需要一个执行方法
ICommand: abstract class extends INotifier {
	// 参数是一个通知类,命令执行的时候可以获取通知里的相关内容
	execute: func(notification: Notification)
}

接下来是代理接口:

/*
 *	IProxy.ooc
 *	代理接口,和官方AS3的一致,只是将对应的数据类型改成了ooc-lang中的
 */

// 一个代理当然包括代理的数据了,然后还有代理类的名称
IProxy: interface {
	getProxyName: func -> String

	setData: func(data: Pointer)

	getData: func -> Pointer

	onRegister: func

	onRemove: func
}

再接下来的中介类接口:

/*
 *	IMediator.ooc
 *	中介类,和官方AS3的差不多
 */

import patterns/observer/Notification

// 一个中介包含了对界面的元素的引用,就是viewComponent了,然后还有中介类的名
IMediator: interface {
	getMediatorName: func -> String

	getViewComponent: func -> Pointer

	setViewComponent: func(viewComponent: Pointer)

	// 列出中介感兴趣的通知,在注册中介的时候需要用到
	listNotificationInterests: func -> String[]

	// 在注册中介的时候,会根据中介感兴趣的通知来注册一个观察者,下面这个方法就是观察者收到通知后调用的了
	handleNotification: func(notification: Notification)

	onRegister: func

	onRemove: func
}

Controller接口:

/*
 *	IController.ooc
 *	和官方AS3的差不多
 */
 
import ICommand
import patterns/observer/Notification

// Controller类提供方法来注册、执行、移除、查询命令
IController: interface {
	
	// 注册命令时需要和通知名称对应起来
	registerCommand: func(notificationName: String, command: ICommand)

	executeCommand: func(notification: Notification)

	removeCommand: func(notificationName: String)

	hasCommand?: func(notificationName: String) -> Bool
}

View接口:

/*
 *	IVeiw.ooc
 *	和官方AS3的差不多
 */
 
import patterns/mediator/Mediator
import patterns/observer/Notification
import patterns/observer/Observer

// View中保存观察者和中介的引用,所以提供方法用来注册、移除、通知观察者,注册、移除、查询、获取中介
IView: interface {
	registerObserver: func(notificationName: String, observer: Observer)

	removeObserver: func(notificationName: String, notifyContext: Pointer)

	notifyObservers: func(notification: Notification)

	registerMediator: func(mediator: Mediator)	

	retrieveMediator: func(mediatorName: String) -> Mediator

	removeMediator: func(mediatorName: String) -> Mediator

	hasMediator?: func(madiatorname: String) -> Bool
}

Model接口:

/*
 *	IModel.ooc
 *	和官方AS3的一致
 */
 
import patterns/proxy/Proxy

// Model类保存数据的代理,不直接保存数据,所以它提供方法注册、查询、移除代理
IModel: interface {
	registerProxy: func(proxy: Proxy)

	retrieveProxy: func(proxyName: String) -> Proxy

	removeProxy: func(proxyName: String) -> Proxy

	hasProxy?: func(proxyName: String) -> Bool
}

最后就是Facade接口了:

/*
*	IFacade.ooc
*	和官方AS3的差不多
*/

import interfaces/INotifier
import patterns/proxy/Proxy
import patterns/mediator/Mediator
import patterns/observer/Notification

// Facade类只是封装MVC这3层的方法,它并没有做其它事
// 我没有继承INotifier啊,因为ooc-lang的语言特性原因,但是Facade类还是可以发通知的,因为
// 在实现类里有继承INotifier
IFacade: interface {
	registerProxy: func(proxy: Proxy)

	retrieveProxy: func(proxyName: String) -> Proxy

	removeProxy: func(proxyName: String) -> Proxy	

	hasProxy?: func(proxyName: String) -> Bool

	registerCommand: func(notificationName: String, command: Pointer)

	removeCommand: func(notificationName: String)

	hasCommand?: func(notificationName: String) -> Bool

	registerMediator: func(mediator: Mediator)

	retrieveMediator: func(mediatorName: String) -> Mediator

	removeMediator: func(mediatorName: String) -> Mediator

	hasMediator?: func(mediatorName: String) -> Bool

	notifyObservers: func(notification: Notification)
}

整个框架的接口就是这样了,和官方的有点点区别。然后应该可以注意到,某些方法我并没有返回一个接口,而是直接返回一个实现类,因为ooc-lang中接口不好用(似乎我说了很多次这话了…)。还有方法的参数类型我也是用实现类的。

后面的文章就是讲具体的实现了。全篇完。?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值