自定义消息机制研究学习(二)——做一些改动,定制自己的消息机制

天我来尝试修改一下代码,以使它更适合我们实际的研发情况。

首先,我们修改一下代码,让它可读性稍微好一点。(原代码参考上文)

monitor.js
var  monitor= (function(){
        function bind(b){
            var queue = this.__MSG_QS__;
            if (!queue[b]) {
                queue[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                queue[b].push(arguments[a])
            }
        }
        function trigger(Y){
            var queue = this.__MSG_QS__[Y.type];
            if (queue == null) {
                return
            }
            for (var a = 0, X = queue.length; a < X; a++) {
                queue[a].handler(Y)
            }
        }
        return {
            ini: function(X){
                X.__MSG_QS__ = {};
                X.bind = bind;
                X.trigger = trigger;
                return X
            }
        }
})();
复制代码

好了,现在我们有一个monitor对象了

现在来说说加入我们使用这个对象有可能要应对的情况。



一、将消息直接通知到函数

如果我们要简单监听某个对象里的某个消息,譬如下面代码中这个对象里的sendData消息

View Code
var obj1=monitor.ini({sendData:function(){
    this.trigger({type:"sendData",data:"1"});
}});
复制代码

我们只是想简单的将这个要发送的数据alert一下,代码如下:

View Code
obj1.bind("sendData",{handler:function(data){
   alert(data.data);
}});
复制代码

  

高兴的事,我们很快写完了。我么可以不要{}呢,也不写handler么?

我们改改monitor,让它能直接将消息发送到函数,对monitor的trigger内的方法做一个简单的更改,如下:

View Code
function trigger(Y){
            var queue = this.__MSG_QS__[Y.type];
            if (queue == null) {
                return
            }
            for (var a = 0, X = queue.length; a < X; a++) {
               if(queue[a].handler)
               {
                   queue[a].handler(Y)
               }
               else
               {
                   queue[a](Y); 
               }
            }
        }
复制代码

  

这样我们就可以直接将消息发送到函数。

当然,这也会给我们带来一点小小的,因为加了if语句的性能损失。10000000次trigger的一个测试数据:1076(未修改前):1134(修改后)——单位毫秒


一个极端点的更改,我们只想把消息传给函数,不传给对象,那么修改如下:

monitor 只传函数
var  monitor= (function(){
        function bind(b){
            var queue = this.__MSG_QS__;
            if (!queue[b]) {
                queue[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
               queue[b].push(arguments[a])
            }
        }
        function trigger(Y){
            var queue = this.__MSG_QS__[Y.type];
            if (queue == null) {
                return
            }
            for (var a = 0, X = queue.length; a < X; a++) {
                   queue[a](Y); 
            }
        }
        return {
            ini: function(X){
                X.__MSG_QS__ = {};
                X.bind = bind;
                X.trigger = trigger;
                return X
            }
        }
})();
复制代码

这样,我们只能bind函数了,这样的方式在一些简单的应用中效果也不错,比如我们用jQuery的bind方法就可以实现很多我们要的效果,为了实现bind函数内this指向消息源头,这里使用call方法就可,代码:

View Code

这样,我们可以基于一个或者数个复杂的对象做一些扩展开发,就像基于dom的click等事件来实现我们想要的效果一样简单。

但如果涉及多个对象直接互相传递消息,只bind到函数就有点限制。如果不是特殊的需求,不建议用这种方式,最好bind到对象,兼容bind到对象和函数,也会让我们少敲一些handler,因此也是个不错的选择




二、new的对象如何绑定monitor

当我们准备用js面向对象开发时,我们干:

View Code
function base()
{}

var obj=new base();
复制代码

那么我们想要在new出来对象上使用monitor模式,少一点使用,我们可以monitor.ini(obj);

那么如果大量类似对象要使用monitor模式呢?譬如

View Code
function Person(name)
{
    this.name=name;
    this.sayHello=function()
    {
        this.trigger({type:"say",msg:"hi,我是"+this.name})
    }
}
复制代码

  我们要创建很多的对象,然后调用他们的sayHello,假设是很多人对不同的对象说话的场景,我们创建一个Person对象就要monitor.ini一下,这种办法很笨

假设你不想修改monitor的代码,你可以这样:

monitor.ini(Person.prototype);

  如果你确实想简单写成如下:

monitor.ini(Person);

  那么只好修改修改monitor代码了:

首先是ini

View Code
ini: function(X){
                if(Object.prototype.toString.call(X)=="[object Function]")
                {
                    var proto=X.prototype;
                    proto.bind = bind;
                    proto.trigger = trigger;                    
                }
                X.bind = bind;
                X.trigger = trigger;
                return X
            }
复制代码

 我去掉了__MSG_QS__ 这个的初始化,因为如果在prototype上绑定__MSG_QS__ 属性的话,每一个bind都会bind到所有对象上,这不是我们的本意,就例如我们希望的是每一个Person说的话,只能由听他说话的人收听到。实现这样的效果还需要在bind,trigger时做一些修改,如下:

bind
trigger
function trigger(Y){
            var qs=this.__MSG_QS__ || {};
            var queue= qs[Y.type] || []; 
            for (var a = 0, X = queue.length; a < X; a++) {
                   if(queue[a].handler)
                   {
                        queue[a].handler(Y)
                   }
                   else
                   {
                        queue[a].call(this,Y);; 
                   }
            }
        }
复制代码

  

 

 ***PS:我把if (queue == null) {return }也去掉了




三、如何绑定类消息

这里的类消息是这样的一种需求,比如接上例,我们要用一个logger记录所有Person讲的话(sayHello()),难道我们创建一百个Person,就要调用一百次bind么?假如只有一处代码才能new Person()那还好说,不会增加我们多少的代码量。但你的new Person已经洒落到代码各处,到处都是。OMG。怎么办?

首先,再剽窃一个jQuery的命名:live,在monitor中加入live代码如下:

live
function live(b)
        {
            var queue = this.prototype.__STATIC_MSG_QS__;
            if (!queue[b]) {
                queue[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                queue[b].push(arguments[a])
            }
        }
复制代码

这段代码与bind区别不大,唯一的区别是它这里使用了this.prototype.__STATIC_MSG_QS__ 而不是this.__MSG_QS__ 我们用__STATIC_MSG_QS__ 来存储类级别的消息队列

所以它是面向function对象的,把ini修改如下

ini
return {
            ini: function(X){
                if(Object.prototype.toString.call(X)=="[object Function]")
                {
                    var proto=X.prototype;
                    proto.__STATIC_MSG_QS__={};
                    proto.bind = bind;
                    proto.trigger = trigger;
                    X.live=live; 
                    
                }
                X.bind = bind;
                X.trigger = trigger;
                return X
            }
        }
复制代码

  如果ini的是function,我们就再function上面绑定了live方法,并且在prototype上增加了__STATIC_MSG_QS__ 

我们还需要修改一下trigger

trigger
function trigger(Y){
            var queue =[];
            var qs=this.__MSG_QS__ || {}; 
            var sqs=this.__STATIC_MSG_QS__|| {}; 
            queue= queue.concat(qs[Y.type] || []);
            queue= queue.concat(sqs[Y.type] || []);
            for (var a = 0, X = queue.length; a < X; a++) {
               if(queue[a].handler)
               {
                   queue[a].handler(Y)
               }
               else
               {
                   queue[a].call(this,Y); 
               }
            }
        }
复制代码

  增加了一些trigger的负担,queue不再直接指向this.__MSG_QS__中获取(queue=this.__MSG_QS__会使两者指向同一内存地址),因为这样如果修改queue变量会直接修改掉__MSG_QS__队列中的值,在这里用了两次concat分别拷贝了对象消息监听者和类消息接听者。

ok,现在我们可以一下就监听所有Person对象的消息了,代码如下:

Person.live("say",{handler: function(data){
 //logger
});
复制代码

  搞定,准备洗洗睡吧!


想要使用类似monitor的人,根据自己的实际需求定制一下。比如你想在监听函数里调用消息源,可以把trigger中queue[a].handler(Y)修改为queue[a].handler(Y,this)等等

修改后的monitor

View Code
var  monitor= (function(){
        function bind(b){
            var queue = this.__MSG_QS__=this.__MSG_QS__ || {};
            if (!queue[b]) {
                queue[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                queue[b].push(arguments[a])
            }
        }
        
        function live(b)
        {
            var queue = this.prototype.__STATIC_MSG_QS__;
            if (!queue[b]) {
                queue[b] = []
            }
            for (var a = 1, X = arguments.length, Y; a < X; a++) {
                queue[b].push(arguments[a])
            }
        }
        
        function trigger(Y){
            var queue =[];
            var qs=this.__MSG_QS__ || {}; 
            var sqs=this.__STATIC_MSG_QS__|| {}; 
          queue= queue.concat(qs[Y.type] || []);
            queue= queue.concat(sqs[Y.type] || []);
            for (var a = 0, X = queue.length; a < X; a++) {
               if(queue[a].handler)
               {
                   queue[a].handler(Y,this)
               }
               else
               {
                   queue[a].call(this,Y,this); 
               }
            }
        }
        return {
            ini: function(X){
                if(Object.prototype.toString.call(X)=="[object Function]")
                {
                    var proto=X.prototype;
                    proto.__STATIC_MSG_QS__={};
                    proto.bind = bind;
                    proto.trigger = trigger;
                    X.live=live; 
                    
                }
                X.bind = bind;
                X.trigger = trigger;
                return X
            }
        }
})();
复制代码

它多了如下一些特性:

1. 可以直接用一个函数侦听消息

2. 可以将function注册为monitor,然后所有function new出来的对象都将自动绑定了monitor

3. 为function增加了live方法,可以方便侦听所有new对象的事件 

4. 将消息源作为第二个参数传给了方法。


附:

这只是简单的一些修改扩展,如果你没有这些需要,简单原始的monitor就非常简洁高效,足够应付一些简单的建模。

实际中我用的类似的monitor模式,不是只有ini的一个{ini:function()}对象,而是一个有bind,trigger,unbind,live,die等方法的function对象,使用继承的方式(比如jQuery.extend)来为{}或new的对象绑定monitor的模式。因此增加了许多的条件判断,性能上要比本文的monitor差一些。

这里的代码都是写本文时随手写的,难免有误,欢迎指正
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值