K_Reverter的网页开发记录

要么不做,要么就当作艺术品来做!

导航

Jla框架介绍(五) 设计模式:模块和实例管理

    今天我要分享的是模块管理,这是Jla框架的一个非常重要的内容,本篇所介绍的模式也将比前面介绍的Jla框架核心存在更多争议,坦白的说,我的这个解决方案面向了复杂的设计模式问题,却并没有提出自己的解决方案,最多只是将问题变得更清晰一些。

 

    大家都知道,要开发一个较为复杂的程序,光靠OOP的思路肯定是解决不了问题,因为OOP解决的是类之间组织的问题, 对于各个功能之间的耦合的解决办法,并没有提出什么实质的解决方案,针对这一点网上有一个流传广泛的《可扩展的JavaScript架构》的解决方案,还有这个PPT,这个解决方案的主要思路如图:

 

 

    总体上来讲,就是沙箱的机制,将各个功能逻辑拆分为一个个的模块,各个模块之间相互独立并且互不耦合,让每一个模块只知道沙箱,而不知道有其他模块,这样打断各个模块之间的关系,就能够保证各个模块的独立性,并且在拿掉一某些模块之后不会影响整个架构的执行。

     这个架构确实能解决很多问题,我在以前开发之中采用的"主体+控件"的模式实际上也是采用这样的机制来解决耦合的问题,只是没有沙箱罢了 。

     但是,我在新的Jla框架设计的时候,发现这个设计模式还是存在一些问题,总体来讲,如下:

    1.任何一个模块,在开发的时候就确定好是一个模块;假设你想简单的使用某一个模块的功能而不想构建一个庞大的沙箱来适应,会比较复杂,同样你如果将一个类改造成一个模块,可能也需要一番功夫,因为每一个模块虽然没有和其他的模块耦合,但是和沙箱本身的耦合太过紧密。

    2.开发的时候,因为模块会将自己的方法和事件赋给沙箱, 假如两个模块采用了同样的方法和事件名称,将引起混乱,这样每个模块在开发的时候必须严格注意不要和别的类重名,影响了模块开发的独立性。

    3.有时候,页面上的功能并不是简单的扁平的结构,可能更多像是一个树形的结构,例如,整个页面分为多个模块,一个模块又由多个更细的模块组成,目前的沙盒模式,可能在按照这种结构开发的时候比较麻烦。

 

    有没有办法可以解决这些问题? 

 

    当我开始仔细分析主体和模块之间的关系时,发现其实就是各个类实例之间的关联,这种关联,其实和类本身之间的关联是比较像的,考虑到这一点,我们可以考虑把上面的沙盒改造成一个简单的实例管理器,而不用实现任何其他功能,各个模块之间的耦合采用类似Jla.require的模式实现即可。

    我们先看看两个简单的模块代码,下面是第一个简单模块:

 

 1 
 2 Jla.require(["Js.Event"],2,function(Event){
 3     /**
 4     Js架构之中用来记录提示消息的模块
 5     @class
 6     */
 7     function App()
 8     {
 9     }
10     App.prototype.log=function(message,level)
11     {
12         Event.trigger(this,"message",[message,level]);
13     }
14     App.modFactory=function(holder,name)
15     {
16         holder.require([],2,function()
17         {
18             holder.set(name,new App());
19         });
20     }
21     Jla.set("Test.logging",App)
22 });

 

 

    从上面这个简单的模块代码可以看出如下特点:

     1.这段代码就是一个简单的类定义 ,这个类的命名空间是"Test.logging",唯一的不同就是增加了modFactory静态方法,当调用这个方法的时候,要求为指定参数的holder创建一个指定名称的实例,当创建完成之后调用holder.set函数注册即可

    2.如果不需要使用模块机制,通过直接去new这个类照样可以使用这个功能逻辑。

    3.模块不需要知道主体是谁,也不关心自己在模块体系之中自己的名称,这样在一个页面上多次使用此模块完全没有问题

    我们再看另一个模块的代码: 

 


Jla.require([
"Js.Event"],2,function(Event){
    
function App(logging,div)
    {
        
this.div=div||document.getElementById("msgDiv");
        Event.bind(logging,
"message",this,this.showMessage);
    }
    App.prototype.showMessage
=function(message)
    {
        
this.div.innerHTML=message||"";
    }
    App.modFactory
=function(holder,name)
    {
        holder.require([
"test.logging"],2,function(logging)
        {
            holder.set(name,
new App(logging));
        });
    }
    Jla.set(
"test.pageLogging",App)
});

 

 

     这个代码使用到了两个模块之间的耦合,从这个实例,我们进一步可以了解如下特点:

     1. 两个模块之间的耦合没有通过holder中转,而是直接向holder请求到了对方模块的实例,之后的操作直接进行,不再通过holder,也没有给Holder添加任何方法或事件,因此不需要担心方法和事件名称冲突的问题

     2. 假如通过new test.pageLogging(new Test.logging())这种方式来直接使用这两个类,照样可以实现功能,因此,模块体系对这两个类来说是可选的,不管有没有模块体系,都可以运行并完成耦合

    下面再看看一个Holder的简单实例代码:

 

 Js.Holder

 

 

    只要继承以上的Js.Holder,就都可以加载自己的子模块,综合以上的三个代码范例可以知道:

      1.模块的开发不再有严格的格式要求,只需要实现modFactory静态方法,任何类都可以成为一个模块;

      2.大部分模块都可以脱离模块体系完成自己的功能,当然,假如模块在运行之中需要调用holder.require方法,就必须要求在模块体系下工作

      3.某个模块本身也可以通过继承Js.Holder来将自身的功能进行进一步的拆分

      4.与沙箱体系不允许模块之间直接交互不同的是,本模式要求每个模块明确的了解自己需要耦合的模块,对目标模块的事件和方法必须有明确的了解。

 

    这个模式对比上面的沙箱模式,似乎各有优缺点,但是究竟哪个好,一些,哪个更适用与何种情况,我还没有想太清楚,但是对于Jla框架来讲,非常关注每个代码单元的重用性和独立性,因此,本文提到的模式似乎会更好一些,希望大家能留下自己的见解,一起讨论一下。

posted on 2011-01-22 11:24  K_Reverter  阅读(1579)  评论(1编辑  收藏  举报