博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript设计模式(Alloy Team)
阅读量:6080 次
发布时间:2019-06-20

本文共 8436 字,大约阅读时间需要 28 分钟。

1.单例模式

单例模式的核心:

(1)确保只有一个实例
(2)提供全局访问

用代理实现单例模式:

var ProxySingletonCreateDiv = (function(){        var instance;        return function( html ){            if ( !instance ){                instance = new CreateDiv( html );            }            return instance;        }    })();

通用的惰性单例模式:创建登陆悬浮窗

//fn保存创建逻辑//单例模式:只创建一次 var getSingle = function( fn ){        var result;        return function(){            return result || ( result = fn .apply(this, arguments ) );        }    };    var createLoginLayer = function(){        var div = document.createElement( 'div' );        div.innerHTML = '我是登录浮窗';        div.style.display = 'none';        document.body.appendChild( div );        return div;    };    var createSingleLoginLayer = getSingle( createLoginLayer );    document.getElementById( 'loginBtn' ).onclick = function(){        var loginLayer = createSingleLoginLayer();        loginLayer.style.display = 'block';    };

2.发布-订阅者模式

(1)首先要指定好谁充当发布者

(2)然后给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者
(3)最后发布消息的时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者函数

var Event = (function(){        var clientList = {},        listen,        trigger,        remove;        listen = function( key, fn ){            if ( !clientList[ key ] ){                clientList[ key ] = [];            }            clientList[ key ].push( fn );        };        trigger = function(){            var key = Array.prototype.shift.call( arguments ),            fns = clientList[ key ];            if ( !fns || fns.length === 0 ){                return false;            }            for( var i = 0, fn; fn = fns[ i++ ]; ){                fn.apply( this, arguments );            }        };        remove = function( key, fn ){            var fns = clientList[ key ];            if ( !fns ){                return false;            }            if ( !fn ){                fns && ( fns.length = 0 );            }else{                for ( var l = fns.length - 1; l >=0; l-- ){                    var _fn = fns[ l ];                    if ( _fn === fn ){                        fns.splice( l, 1 );                    }                }            }        };        return {            listen: listen,            trigger: trigger,            remove: remove        }    })();

给所有的对象都动态安装一个发布-订阅功能:

var installEvent = function( obj ){        for ( var i in event ){            obj[ i ] = event[ i ];        }    };

3.装饰着模式

(1)装饰者模式可以动态的给某个对象添加一些额外的职责,而不会影响从这个类中派生出的其他对象。

(2)装饰者也是包装器:装饰者模式将一个对象嵌入到另一个对象中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链。

3-1.在不改变原来函数的情况下给函数增加新的功能

var a=function(){        alert(1);    }    var _a = a;    a=function(){        _a();        alert(2);    }

但是这样做会带来两个问题:必须维护_a这个中间变量;存在this被劫持的问题

3-2.用AOP装饰函数

Function.prototype.before = function( beforefn ){        var __self = this; // 保存原函数的引用        return function(){ // 返回包含了原函数和新函数的"代理"函数            beforefn.apply( this, arguments ); // 执行新函数,且保证this 不被劫持,新函数接受的参数        // 也会被原封不动地传入原函数,新函数在原函数之前执行            return __self.apply( this, arguments ); // 执行原函数并返回原函数的执行结果,        // 并且保证this 不被劫持    }}Function.prototype.after = function( afterfn ){    var __self = this;    return function(){        var ret = __self.apply( this, arguments );        afterfn.apply( this, arguments );        return ret;    }};//调用:重写原来函数formSubmit = formSubmit.before( validata );

4.策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

4-1.使用策略模式计算奖金
绩效为S的人年终奖金是工资的4倍,绩效为A的人年终奖金是工资的3倍,绩效为B的人年终奖金是工资的2倍

var performanceS = function(){};    performanceS.prototype.calculate = function( salary ){        return salary * 4;    };    var performanceA = function(){};    performanceA.prototype.calculate = function( salary ){        return salary * 3;    };    var performanceB = function(){};    performanceB.prototype.calculate = function( salary ){        return salary * 2;    };    //接下来定义奖金类Bonus:    var Bonus = function(){        this.salary = null; // 原始工资        this.strategy = null; // 绩效等级对应的策略对象    };    Bonus.prototype.setSalary = function( salary ){        this.salary = salary; // 设置员工的原始工资    };    Bonus.prototype.setStrategy = function( strategy ){        this.strategy = strategy; // 设置员工绩效等级对应的策略对象    };    Bonus.prototype.getBonus = function(){ // 取得奖金数额        return this.strategy.calculate( this.salary ); // 把计算奖金的操作委托给对应的策略对象    };    var bonus = new Bonus();    bonus.setSalary( 10000 );    bonus.setStrategy( new performanceS() ); // 设置策略对象    console.log( bonus.getBonus() ); // 输出:40000

4-2.javascript版本的策略模式

var strategies = {        "S": function( salary ){            return salary * 4;        },        "A": function( salary ){            return salary * 3;        },        "B": function( salary ){            return salary * 2;        }    };    var calculateBonus = function( level, salary ){        return strategies[ level ]( salary );    };    console.log( calculateBonus( 'S', 20000 ) ); // 输出:80000    console.log( calculateBonus( 'A', 10000 ) ); // 输出:30000

通过使用策略模式重构代码,我们消除了原来程序中大片的条件分支代码。所有和计算奖金的逻辑不再放在context中,而是分布在各个策略对象中。每个策略对象负责的算法已被各自封装在对象内部。当我们对这些策略对象发出“计算奖金”请求时,它们会返回各自不同的计算结果。

4-3.用策略模式进行表单校验

(1)用户名不能为空
(2)密码长度不能少于6位
(3)手机号码必须符合格式

    
请输入用户名:
请输入密码:
请输入手机号码:

5.代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

5-1.小明追女神的故事
小明遇到了他的女神A,打算送一朵鲜花来表白。刚好小明打听到他和A有一个共同的好友B,于是小明决定让B来替自己来完成这件事。

var Flower = function(){};var xiaoming = {    sendFlower: function( target ){        var flower = new Flower();        target.receiveFlower( flower );    }};var A = {    receiveFlower: function( flower ){        console.log( '收到花 ' + flower );    }};xiaoming.sendFlower( A );//接下来,我们引入代理B,即小明通过B 来给A 送花:var Flower = function(){};var xiaoming = {    sendFlower: function( target){        var flower = new Flower();        target.receiveFlower( flower );    }};var B = {    receiveFlower: function( flower ){        A.receiveFlower( flower );        90 第6 章 代理模式    }};var A = {    receiveFlower: function( flower ){        console.log( '收到花 ' + flower );    }};xiaoming.sendFlower( B );//然后选择A 心情好的时候把花转交给A,代码如下:var Flower = function(){};var xiaoming = {    sendFlower: function( target){        var flower = new Flower();        target.receiveFlower( flower );    }};var B = {    receiveFlower: function( flower ){        A.listenGoodMood(function(){ // 监听A 的好心情            A.receiveFlower( flower );        });    }};var A = {    receiveFlower: function( flower ){        console.log( '收到花 ' + flower );    },    listenGoodMood: function( fn ){        setTimeout(function(){ // 假设10 秒之后A 的心情变好            fn();        }, 10000 );    }};xiaoming.sendFlower( B );var myImage = (function(){    var imgNode = document.createElement( 'img' );    document.body.appendChild( imgNode );    return {        setSrc: function( src ){            imgNode.src = src;        }    }})();

5-2.保护代理与虚拟代理

保护代理:比如B可以帮助A过滤掉一些请求,如送花的人中年龄较大的
虚拟代理:new Flower可能是非常昂贵的,这时候需要B代理去执行,代理B在A心情好的时候再执行。
5-3.虚拟代理实现图片预加载

var myImage = (function(){        var imgNode = document.createElement( 'img' );        document.body.appendChild( imgNode );        return function( src ){            imgNode.src = src;        }    })();    var proxyImage = (function(){        var img = new Image;        img.onload = function(){            myImage( this.src );        }        return function( src ){            myImage( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );            img.src = src;        }    })();    proxyImage( 'http:// imgcache.qq.com/music// N/k/000GGDys0yA0Nk.jpg' );

纵观整个程序,我们并没有改变或者增加myImage接口,但是通过代理对象,实际上是给系统添加了新的行为:给img节点设置 src和图片预加载这两个功能。

5-4.虚拟代理合并http请求

    1    2    3    4    5    6    7    8    9

script.js:

var synchronousFile = function( id ){        console.log( '开始同步文件,id 为: ' + id );    };    var proxySynchronousFile = (function(){        var cache = [], // 保存一段时间内需要同步的ID        timer; // 定时器        return function( id ){            cache.push( id );            if ( timer ){ // 保证不会覆盖已经启动的定时器                return;            }            timer = setTimeout(function(){            synchronousFile( cache.join( ',' ) ); // 2 秒后向本体发送需要同步的ID 集合            clearTimeout( timer ); // 清空定时器            timer = null;            cache.length = 0; // 清空ID 集合        }, 2000 );        }    })();    var checkbox = document.getElementsByTagName( 'input' );    for ( var i = 0, c; c = checkbox[ i++ ]; ){        c.onclick = function(){            if ( this.checked === true ){                proxySynchronousFile( this.id );            }        }    };

转载地址:http://bzegx.baihongyu.com/

你可能感兴趣的文章
华为Access、Hybrid和Trunk的区别和设置
查看>>
centos使用docker下安装mysql并配置、nginx
查看>>
关于HTML5的理解
查看>>
需要学的东西
查看>>
Internet Message Access Protocol --- IMAP协议
查看>>
Linux 获取文件夹下的所有文件
查看>>
对 Sea.js 进行配置(一) seajs.config
查看>>
第六周
查看>>
解释一下 P/NP/NP-Complete/NP-Hard 等问题
查看>>
javafx for android or ios ?
查看>>
微软职位内部推荐-Senior Software Engineer II-Sharepoint
查看>>
sql 字符串操作
查看>>
【转】Android布局优化之ViewStub
查看>>
网络安全管理技术作业-SNMP实验报告
查看>>
根据Uri获取文件的绝对路径
查看>>
Flutter 插件开发:以微信SDK为例
查看>>
.NET[C#]中NullReferenceException(未将对象引用到实例)是什么问题?如何修复处理?...
查看>>
边缘控制平面Ambassador全解读
查看>>
Windows Phone 7 利用计时器DispatcherTimer创建时钟
查看>>
程序员最喜爱的12个Android应用开发框架二(转)
查看>>