上一节将这三个核心层需要的类都实现了,这节就讲下Model、View、Controller这三层的具体实现。这三个层都用到了单例模式。
Model层:
我们并不需要在这个层里保存任何数据,所有数据都是通过代理来获取操作的,这个层只需要保存所有代理的引用就可以了。具体的数据类型可以用另外的类来声明,然后将这个数据保存到代理中。该层提供方法注册、获取、移除代理。
/*
* Model.ooc
* 数据层
*/
import structs/HashMap
import interfaces/IModel
import patterns/proxy/Proxy
Model: class implements IModel {
// 一些脚本语言中的数据使用非常方便,但是ooc-lang中的数据没这么方便
// 所以用一个哈希表来保存所有代理
proxyMap: HashMap
// 类的唯一实例
instance: static Model
SINGLETON_MSG := "Model Singleton already constructed!"
init: func {
// 为构造函数添加一些限制,使其只能实例化一个类的实例
if (This instance != null) {
Exception new(SINGLETON_MSG) throw()
}
"[ Model ] new()" println()
instance = this
proxyMap = HashMap new()
initializeModel()
}
// 初始化Model层。一般情况下我们只需要用这一个Model层就行了
// 如果我们需要自己实现一个具体的Model层,就要重写这个方法,在这里边进行一些初始化操作
initializeModel: func {
"[ Model ] initializeModel()" println()
}
// 获取类的唯一实例,声明为静态函数
getInstance: static func -> Model {
if (This instance == null) {
This instance = Model new()
}
return This instance
}
// 注册一个代理,参数就是一个代理的实例了
registerProxy: func(proxy: Proxy) {
"[ Model ] registerProxy() #{proxy getProxyName()}" println()
proxyMap add(proxy getProxyName(), proxy)
proxy onRegister()
}
// 通过代理名称获取代理的实例
retrieveProxy: func(proxyName: String) -> Proxy {
"[ Model ] retrieveProxy() #{proxyName}" println()
proxyMap get(proxyName)
}
// 查询是否存在这个代理
hasProxy?: func(proxyName: String) -> Bool {
proxyMap get(proxyName) != null
}
// 从代理列表中移除这个代理
removeProxy: func(proxyName: String) -> Proxy {
"[ Model ] removeProxy() #{proxyName}" println()
proxy := proxyMap get(proxyName)
if (proxy != null) {
proxyMap remove(proxyName)
proxy onRemove()
}
return proxy
}
}
View层:
该层只负责保存中介和观察者的引用,并提供方法注册、获取、移除中介或观察者。而具体的界面元素,一般是放在另一个单独的类里,然后在代理中保存该类的引用。
/*
* View.ooc
* 界面层
*/
import structs/[HashMap, ArrayList]
import interfaces/IView
import patterns/mediator/Mediator
import patterns/observer/[Observer, Notification]
View: class implements IView {
// 中介列表,用于保存中介的引用
mediatorMap: HashMap
// 观察者列表,用于保存观察者的引用
observerMap: HashMap>
// 类的唯一实例
instance: static View
SINGLETON_MSG := "View Singleton already constructed!"
init: func {
// 限制构造函数,使其只能实例化一个类实例
if (This instance != null) {
Exception new(SINGLETON_MSG) throw()
}
"[ View ] new()" println()
This instance = this
mediatorMap = HashMap new()
observerMap = HashMap> new()
initializeView()
}
// 初始化View层。一般情况下我们只需要用这一个View层就行了
// 如果我们需要自己实现一个具体的View层,就要重写这个方法,在这里边进行一些初始化操作
initializeView: func {
"[ View ] initializeView()" println()
}
// 获取类的唯一实例,声明为静态函数,这样就可以不用实例化类也能访问该函数
getInstance: static func -> View {
if (This instance == null) {
This instance = View new()
}
return This instance
}
// 注册一个观察者,参数为对应的通知名称和一个观察者实例
registerObserver: func(notificationName: String, observer: Observer) {
"[ View ] registerObserver() #{notificationName}" println()
// 从观察者列表中获取对应通知的观察者链表,一个通知可以注册多个观察者
observerList := observerMap get(notificationName)
// 如果这个链表不为空
if (observerList != null) {
// 直接将观察者添加到这个链表中
observerList add(observer)
} else {
// 否则先建一个链表,再添加
observerList = ArrayList new()
observerList add(observer)
observerMap add(notificationName, observerList)
}
}
// 通知观察者,参数为对应的通知
notifyObservers: func(notification: Notification) {
"[ View ] notifyObservers() #{notification getName()}" println()
// 先判断对应的观察者列表是否为空
if (observerMap get(notification getName()) != null) {
// 官方的AS3版中,将观察者列表复制了一份,而不是在原来的引用上调用观察者的方法
// 原因是说避免在调用的过程中修改观察者的引用?这个我也不确定会不会改变
observerList := observerMap get(notification getName()) clone()
// 遍历每个观察者,并调用它的方法执行对应的通知函数
observerList each(|observer| {
observer notifyObserver(notification)
})
}
}
// 移除观察者
removeObserver: func(notificationName: String, notifyContext: Pointer) {
"[ View ] removeObserver() #{notificationName}" println()
observerList := observerMap get(notificationName)
if (observerList != null) {
for (i in 0..observerList getSize()) {
observerList removeAt(i)
}
observerMap remove(notificationName)
}
}
// 注册一个中介
registerMediator: func(mediator: Mediator) {
// 避免重复注册
if (mediatorMap get(mediator getMediatorName()) != null) {
return
}
"[ View ] registerMediator() #{mediator getMediatorName()}" println()
mediatorMap add(mediator getMediatorName(), mediator)
// 获取该中介感兴趣的通知
interests := mediator listNotificationInterests()
// 如果有感兴趣的通知,需要注册对应的观察者来执行通知函数。
if (interests length > 0) {
// 使用闭包来解决类成员方法作为参数时会默认多一个this指针作为参数,但是声明为static方法却无法重写时的问题
executeCommand := func(notification: Notification) {
mediator handleNotification(notification)
}
// 新建一个观察者
observer := Observer new(executeCommand, mediator)
// 为每个感兴趣的通知注册一个观察者
for (i in 0..interests length) {
registerObserver(interests[i], observer)
}
}
mediator onRegister()
}
// 根据中介名获取对应的中介
retrieveMediator: func(mediatorName: String) -> Mediator {
"[ View ] retrieveMediator() #{mediatorName}" println()
mediatorMap get(mediatorName)
}
// 从中介列表中移除对应的中介
removeMediator: func(mediatorName: String) -> Mediator {
"[ View ] removeMediator() #{mediatorName}" println()
mediator := mediatorMap get(mediatorName)
// 移除中介的过程中,还需把中介注册了的观察者给移除,因为不需要用到了
if (mediator != null) {
interests := mediator listNotificationInterests()
if (interests length > 0) {
for (i in 0..interests length) {
removeObserver(interests[i], mediator)
}
}
mediatorMap remove(mediatorName)
mediator onRemove()
}
return mediator
}
// 查询中介列表中是否有对应的中介
hasMediator?: func(mediatorName: String) -> Bool {
mediatorMap get(mediatorName) != null
}
}
Controller层:
该层是负责Model层和View层的沟通的,具体的逻辑都分布在了一个个的Command类中,它只保存这些命令的引用,并提供注册、移除命令的方法。它本身并没有写其它逻辑的。
/*
* Controller.ooc
* 控制层
*/
import structs/HashMap
import interfaces/[IController, IView, ICommand, INotification]
import core/View
import patterns/observer/[Observer, Notification]
Controller: class implements IController {
// view层的引用,因为需要用到里边注册观察者的方法
view: View
// 命令列表,用于保存所有命令的实例
commandMap: HashMap
// 类的唯一实例
instance: static Controller
SINGLETON_MSG := "Controller Singleton already constructed!"
init: func {
// 限制构造函数,使其只能实例话一个类实例
if (This instance != null) {
Exception new(SINGLETON_MSG) throw()
}
"[ Controller ] new()" println()
This instance = this
commandMap = HashMap new()
initializeController()
}
// 初始化Controller层。一般情况下我们只需要用这一个Controller层就行了
// 如果我们需要自己实现一个具体的Controller层,就要重写这个方法,在这里边进行一些初始化操作
initializeController: func {
"[ Controller ] initializeController()" println()
view = View getInstance()
}
getInstance: static func -> Controller {
if (This instance == null) {
This instance = Controller new()
}
return This instance
}
// 执行对应通知的命令,会作为一个观察者的回调函数
executeCommand: func(notification: Notification) {
"[ Controller ] executeCommand() #{notification getName()}" println()
// 先从命令列表里获取对应的命令
command := commandMap get(notification getName())
// 不存在的话直接返回
if (command == null) {
return
}
// 存在就执行,不管是SimpleCommand还是MacroCommand,只需执行execute()这个方法就行了
command execute(notification)
}
// 注册一个命令,参数为通知名称和对应的命令实例
registerCommand: func(notificationName: String, command: ICommand) {
"[ Controller ] registerCommand() #{notificationName}" println()
// 这里的逻辑和官方AS3版的差不多,但是我感觉官方的逻辑有点点问题
// 看下面的代码可以知道,一个通知名称只能注册一个观察者,但是View层注册观察者的
// 方法有说-一个通知可以注册多个观察者的,但是这里的逻辑只能注册一个
// 我不清楚是不是故意这样做的
if (commandMap get(notificationName) == null) {
// 这里将executeCommand这个方法重新封装了一下,是为了避免直接将它作为回调传给
// observer的话,会默认传入一个this指针的问题,导致回调函数类型不匹配
exeCmd := func(notification: Notification) {
executeCommand(notification)
}
// 注册一个观察者监听这个通知
view registerObserver(notificationName, Observer new(exeCmd, this))
}
// 添加到命令列表
commandMap add(notificationName, command)
}
// 查询是否有对应的命令
hasCommand?: func(notificationName: String) -> Bool {
commandMap get(notificationName) != null
}
// 移除对应的命令
removeCommand: func(notificationName: String) {
"[ Controller ] removeCommand() #{notificationName}" println()
if (hasCommand?(notificationName)) {
// 同时也要移除对应的观察者
view removeObserver(notificationName, this)
commandMap remove(notificationName)
}
}
}
核心层代码就这样,ooc-lang实现的和官方AS3版的有点点区别,但逻辑都是一样的。下一节把Facade类讲完就没了。