甘露模型的装饰模式实现

这是我第二次针对甘露模型做专题了。这一次是基于最新版本的甘露模型做设计模式的探讨实现。

开篇之前,先说几句废话:

javascript运行于浏览器之上,而设计模式一般是在大型项目中才有用武之地,这二者一结合,也便产生了一个中心,两个基本点。

所谓 一个中心稳定运行,性能至上

浏览器上面运行的程序,想要做大一点的项目,首先是要过性能这一关。而甘露模型实现了完美的内存资源节约和性能优化,是架构核心的不二之选。


所谓 两个基本点:1,架构清晰; 2,易于扩展

基于甘露模型本身的面向对象思想,完全可以用来实现GOF23,所以,在架构和扩展上既然有了设计模式做铺垫,也就不必担心什么大问题了。

本文出处:http://www.cnblogs.com/kvspas/archive/2009/01/14/1375913.html

代码的例子描述来自 terrylee 的装饰模式C#版本, http://terrylee.cnblogs.com/archive/2006/03/01/340592.html

关于装饰模式的详细解释,请看 terrylee 的装饰模式C#版本,这里我就不多详解了。

废话完毕,直接上代码:


        
// ============甘露模型开始 =================================

        
// 定义类的语法甘露:Class()
         // 最后一个参数是JSON表示的类定义
         // 如果参数数量大于1个,则第一个参数是基类
         // 第一个和最后一个之间参数,将来可表示类实现的接口
         // 返回值是类,类是一个构造函数
         function  Class()  {
            
var aDefine = arguments[arguments.length - 1]; //最后一个参数是类定义
            if (!aDefine) return;
            
var aBase = arguments.length > 1 ? arguments[0] : object; //解析基类

            
function prototype_() { }//构造prototype的临时函数,用于挂接原型链
            prototype_.prototype = aBase.prototype;  //准备传递prototype
            var aPrototype = new prototype_();    //建立类要用的prototype

            
for (var member in aDefine)  //复制类定义到当前类的prototype
                if (member != "Create")    //构造函数不用复制
                aPrototype[member] = aDefine[member];

            
//根据是否继承特殊属性和性能情况,可分别注释掉下列的语句
            if (aDefine.toString != Object.prototype.toString)
                aPrototype.toString 
= aDefine.toString;
            
if (aDefine.toLocaleString != Object.prototype.toLocaleString)
                aPrototype.toLocaleString 
= aDefine.toLocaleString;
            
if (aDefine.valueOf != Object.prototype.valueOf)
                aPrototype.valueOf 
= aDefine.valueOf;

            
if (aDefine.Create)  //若有构造函数
                var aType = aDefine.Create  //类型即为该构造函数
            else    //否则为默认构造函数
                aType = function() {
                    
this.base.apply(this, arguments);   //调用基类构造函数
                }
;

            aType.prototype 
= aPrototype;   //设置类(构造函数)的prototype
            aType.Base = aBase;             //设置类型关系,便于追溯继承关系
            aType.prototype.Type = aType;   //为本类对象扩展一个Type属性
            return aType;   //返回构造函数作为类
        }
;

        
// 根类object定义:
         function  object()  { }      // 定义小写的object根类,用于实现最基础的方法等
        object.prototype.isA  =   function (aType)    // 判断对象是否属于某类型
         {
            
var self = this.Type;
            
while (self) {
                
if (self == aType) return true;
                self 
= self.Base;
            }
;
            
return false;
        }
;

        object.prototype.base 
=   function ()   // 调用基类构造函数
         {
            
var Base = this.Type.Base;  //获取当前对象的基类  
            if (!Base.Base)  //若基类已没有基类
                Base.apply(this, arguments)     //则直接调用基类构造函数
            else    //若基类还有基类         
            {
                
this.base = MakeBase(Base);     //先覆写this.base
                Base.apply(this, arguments);    //再调用基类构造函数
                delete this.base;               //删除覆写的base属性
            }
;

            
function MakeBase(Type) //包装基类构造函数
            {
                
var Base = Type.Base;
                
if (!Base.Base) return Base; //基类已无基类,就无需包装
                return function()   //包装为引用临时变量Base的闭包函数
                {
                    
this.base = MakeBase(Base);     //先覆写this.base
                    Base.apply(this, arguments);    //再调用基类构造函数
                }
;
            }
;
        }
;


    
// ========== 甘露模型完毕,下面是装饰者模式 ====================

    
    
// 抽象基类
     var  Ilog  =  Class(
        
{
            write: 
"this is an abstract method" //这里只能随便用个东西来代替 C# 的 public abstract void write();
        }

    );

    
// 记录到文本文件
     var  TextLog  =  Class(Ilog, 
        
{
            write: 
function() {

                alert(
"记录到文本文件!");
            }

        }

    );

    
// 记录到数据库
     var  DbLog  =  Class(Ilog, 
        
{
        write: 
function() {

            alert(
"记录到数据库!");
            }

        }

    );

    
// 抽象功能扩展,所有的功能扩展都从这个类继承
     var  ILogWrapper  =  Class(Ilog, 
    
{
        
        Create: 
function(_log) {

            
this.log = _log;
        }
,

        write: 
"this is an abstract method" //这里只能随便用个东西来代替 C# 的 public abstract void write();
        //这个write其实可以不要的,但那是托了javascript的运行机制的福气,既然是模拟OOP,就还是加上比较好。
    }

    );

    
// 具体功能扩展1
     var  LogErrorWrapper  =  Class(ILogWrapper,
    
{
        Create: 
function(_log) {

            
this.base(_log);
        }
,
        write: 
function() {
        
            alert(
"具体功能扩展:LogErrorWrapper");
            
this.log.write();//重点
        }

    }

    );

    
// 具体功能扩展2
     var  LogPriorityWrapper  =  Class(ILogWrapper,
    
{
        Create: 
function(_log) {

            
this.base(_log);
        }
,
        write: 
function() {

            alert(
"具体功能扩展:LogPriorityWrapper");
            
this.log.write();//重点
        }

    }

    ); 

    
// 客户端实现
     function  main()  {

        
var base = new TextLog();
        
        
var e = new LogErrorWrapper(base);
        
var e2 = new LogPriorityWrapper(e);
        
        e2.write();

    }


    main();
   

 

 甘露模型的装饰模式实现

 装饰模式是为了避免随着功能需求的增多而发生子类膨胀。在javascipt中,我们其实可以有更加优雅的写法:直接扩充class的property,三两句话就解决问题了。为什么还要用这种简直是茴字的四个写法一样的代码呢?这就需要从问题的根本上谈起:既然这是描述设计模式,而设计模式本来就是为了解决大型的、长期可维护、可扩充的代码而存在的,那么我们首先要关注的就是大型项目的长远问题。

长远问题的第一点:随着需求的不断增多,基类的property也不断增多,很多时候一个对象的生存期仅仅是做一件事情(仅需要一个property),而它在创建期上却加载了100个property。

长远问题的第二点:直接使用逐渐增加的property扩展,很难说会不会今天喝醉了搞了个闭包进来,没人发觉,明天弄了个依赖全局对象的东西进来,也没人发觉。半年之后才发觉程序变得很慢很难维护的时候,这种隐式杀手是不可能找得出来的。

这就是大型长期项目不能简单使用原型扩展的原因。

好了,全文完,理论上还存在22个续篇。看回帖数来决定要不要写。

 

你可能感兴趣的:(装饰模式)