zoukankan      html  css  js  c++  java
  • PureMVC(JS版)源码解析(九):View类

         在讲解View类之前,我们先回顾一下PureMVC的模块划分:

         在PureMVC中M、V、C三部分由三个单例类管理,分别是Model/View/Controller。PureMVC中另外一个单例类——Facade。Facade提供了与MVC三个单例类(核心类)通信的唯一接口。这4个单例类构建了PureMVC的骨架。
         在游戏开发中,一个游戏是由多个模块组成,如主场景模块,战斗模块等等,每个模块通常都是单独的Model/View/Controller,显然PureMVC的4个单例类是无法满足需求的,它就提供了Proxy/Mediator/Command来解决问题。
         Proxy/Mediator/Command分别对应MVC中的Model/View/Controller,也分别有对应的单例管理,Model保存所有的Proxy引用、View保存所有的Mediator引用,Controller保存所有的Command映射。
         这篇博客开始,我们就要开始讲解PureMVC的三大核心类,先看看View类。
         View保存了所有的Mediator引用,它有一个mediatorMap数组,用来存放所有的Mediator引用。
    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类的observerMap属性主要用于存放消息名(notificationName)和observer(观察者)之间的映射,一个消息名可以对应几个observer,所以如果检索到observerMap中存在notificationName,则把observer推入相应的数组中。observerMap大致的数据格式如下:
    {“notificationName1":[observer1,observer2],"notificationName2":[observer3,observer4]} 
     
    同时,除了注册观察者【registerObserver()】,还需要从observerMap中移除观察者(removeObserver):
    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;
    };

     

         根据Multiton模式(Multiton模式不理解的可以自行搜索)的设计原理,我们可以通过一个key值调用getInstance()方法来获取某个View实例:
    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类的思维导图。

  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/iRavior/p/3362700.html
Copyright © 2011-2022 走看看