在讲解View类之前,我们先回顾一下PureMVC的模块划分:
View.prototype.mediatorMap = null;
我们知道Mediator类有一个onRegister()方法,当Mediator对象在facade中注册时调用的,实际上Mediator对象的注册是通过调用View单例的registerMediator()方法来实现。
View.prototype.registerMediator = function(mediator) { if(this.mediatorMap[mediator.getMediatorName()] != null) { return; } //mediator类继承Notifier类,这是初始化Notifier,给mediator的facade属性赋值 mediator.initializeNotifier(this.multitonKey); this.mediatorMap[mediator.getMediatorName()] = mediator; //返回mediator感兴趣的消息 var interests = mediator.listNotificationInterests(); // register mediator as an observer for each notification if(interests.length > 0) { //创建一个Observer,把notification和mediator关联起来 var observer = new Observer(mediator.handleNotification, mediator); for(var i = 0; i < interests.length; i++) { this.registerObserver(interests[i], observer); } } //在这里调用了mediator的onRegister()方法 mediator.onRegister(); }
从这段代码中可以明白Mediator类onRegister()方法的调用机制了,这段代码中还有一个地方需要我们去深入研究:
//这段代码什么意思呢?
this.registerObserver(interests[i], observer);
registerObserver(),通过方法名我们可以知道它是用来注册Observer对象的,我们看一下的实现代码:
View.prototype.registerObserver = function(notificationName, observer) { if(this.observerMap[notificationName] != null) { this.observerMap[notificationName].push(observer); } else { this.observerMap[notificationName] = [observer]; } };
View.prototype.removeObserver = function(notificationName, notifyContext) { //通过notificationName,可以检索到接受该消息的Observer,返回一个数组 var observers = this.observerMap[notificationName]; for(var i = 0; i < observers.length; i++) { if(observers[i].compareNotifyContext(notifyContext) == true) { //移除observer observers.splice(i, 1); break; } } if(observers.length == 0) { delete this.observerMap[notificationName]; } };
另外,我们知道Mediator类还有一个与onRegister()(注册)方法对应的onRemove()(注销)方法,是Mediator对象在facade中注销时调用的,Mediator对象的注销是通过调用View单例的removeMediator()方法来实现:
View.prototype.removeMediator = function(mediatorName) { var mediator = this.mediatorMap[mediatorName]; if(mediator) { // for every notification the mediator is interested in... var interests = mediator.listNotificationInterests(); for(var i = 0; i < interests.length; i++) { // remove the observer linking the mediator to the notification this.removeObserver(interests[i], mediator); } // remove the mediator from the map delete this.mediatorMap[mediatorName]; //触发mediator对象的onRemove方法 mediator.onRemove(); } return mediator; };
mediator对象除了在facade中注册(registerMediator),从facade中注销(removeMediator),还有一个很重要的方法,就是从facade里面检索mediator( retrieveMediator):
View.prototype.retrieveMediator = function(mediatorName) { return this.mediatorMap[mediatorName]; };
通过上面的例子,我们可以知道Mediator类onRegister(),onRemove()方法的使用原理(与View类的registerMediator(),removeMediator,retrieveMediator()对应)和怎么注册观察者(registerObserver())、怎么移除观察者(removeMediator())。View类还有一个重要的方法就是给所有的观察者发送消息(notifyObservers()),触发观察者的消息处理函数。
View.prototype.notifyObservers = function(notification) { // SIC if(this.observerMap[notification.getName()] != null) { var observers_ref = this.observerMap[notification.getName()], observers = [], observer for(var i = 0; i < observers_ref.length; i++) { observer = observers_ref[i]; observers.push(observer); } for(var i = 0; i < observers.length; i++) { observer = observers[i]; //出发了观察者的消息处理函数 observer.notifyObserver(notification); } } };
到目前为止,我们应该可以大致弄清楚mediator对象的消息处理机制了。
我们在Mediator/Command/Proxy通过调用继承自Notifier类的sendNotification()发送消息,实际上是调用View单例的notifyObservers()方法。
View类是个多例类,它用instanceMap来存放View类的实例,我们来看一下它的构造函数:
function View(key) { if(View.instanceMap[key] != null) { throw new Error(View.MULTITON_MSG); }; this.multitonKey = key; View.instanceMap[this.multitonKey] = this; this.mediatorMap = []; this.observerMap = []; this.initializeView(); }; /** * @protected * Initialize the Singleton View instance * * Called automatically by the constructor, this is your opportunity to * initialize the Singleton instance in your subclass without overriding the * constructor * * @return {void} */ View.prototype.initializeView = function() { return; };
View.getInstance = function(key) { if (null == key) return null; if(View.instanceMap[key] == null) { View.instanceMap[key] = new View(key); };
//实际上是从instanceMap数组中检索 return View.instanceMap[key]; };
总结一下,View类的结构相对于Mediator、Command、Proxy类要复杂许多,但他是PureMVC消息机制的核心,里面的很多方法我们需要记住,反复揣摩,特别是notifyObservers()。最后,附上View类的思维导图。