《Javascript设计模式与开发实践》关于设计模式典型代码的整理(上):单例模式、策略模式、代理模式、迭代器模式、发布-订阅模式、命令模式、组合模式

1、单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  •  使用闭包封装私有变量
// 使用闭包创建单例
var user = (function () {
    var _name = 'sven',
        _age = 29;
    
    return {
        getUserInfo: function () {
            return _name + '-' + _age;
        }
    }
})();
  • 惰性单例(只在合适的时候创建对象,并且之创建唯一的一个,试用于dom重复生成、事件绑定等场景)
// 惰性单例生成
var getSingle = function (fn) {
    var result;
    return function () {
        return result || (result = fn.apply(this, arguments));
    }
};

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

// 策略模式
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));
 console.log(calculateBonus('A', 10000));

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

// 虚拟代理
var myImage = (function () {
   var imgNode = document.createElement('img');
   document.body.appendChild(imgNode);

   return {
       setSrc: function (src) {
           imgNode.src = src;
       }
   }
})();

var proxyImage = (function () {
    var img = new Image;
    img.onload = function () {
        myImage.setSrc(this.src);
    }
    return {
        setSrc: function (src) {
            myImage.setSrc('file:// /C:/Users/svenzeng/Desktop/loading.gif');
            img.src = src;
        }
    }
})();
// 测试
proxyImage.setSrc('http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );
// 缓存代理
var mult = function () {
    console.log('开始计算乘积');
    var a = 1;
    for(var i = 0, l = arguments.length; i < l; i++) {
       a = a * arguments[i]; 
    }
    return a;
}

var proxyMult = (function () {
    var cache = {};
    return function () {
        var args = Array.prototype.join.call(arguments, ',');
        if(args in cache) {
            return cache[args];
        }
        return cache[args] = mult.apply(this, arguments);
    }
})();
// 测试
proxyMult(1,2,3,4);
proxyMult(1,2,3,4);

4、迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

// 迭代器模式
var each = function(ary, callback) {
    for (var i = 0, l = ary.length; i < l; i++) {
        callback.call(ary[i], i, ary[i]);
    }
};
// 测试
each([1, 2, 3], function(i, n) {
    alert ([i, n]);
});

5、发布-订阅模式:它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。

// 发布-订阅模式
var event = {
    clientList: [],
    listen: function (key, fn) {
        if (!this.clientList[key]) {
            this.clientList[key] = [];
        }
        this.clientList[key].push(fn);  // 订阅的消息添加进缓存列表
    },
    trigger: function () {
        var key = Array.prototype.shift.call(arguments);
            fns = this.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 = this.clientList[key];
        if (!fns) { // 如果 key 对应的消息没有被人订阅,则直接返回
            return false;
        }
        if (!fn) {  // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅
            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);   // 删除订阅者的回调函数
                }
            }
        }
    }
};
// 安装发布—订阅功能
var installEvent = function (obj) {
    for (var i in event) {
        obj[i] = event[i];
    }
};
// 测试
var salesOffices = {};
installEvent( salesOffices );

salesOffices.listen( 'squareMeter88', fn1 = function( price ){
    console.log( '价格= ' + price );
}); // 小明订阅消息
salesOffices.listen( 'squareMeter88', fn2 = function( price ){
    console.log( '价格= ' + price );
}); // 小红订阅消息
salesOffices.remove( 'squareMeter88', fn1 );
salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000

6、命令模式:用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

// 命令模式
var bindClick = function (button, func) {
    button.onclick = func;
};

var MenuBar = {
    refresh: function () {
        console.log('刷新菜单界面');
    }
};

var SubMenu = {
    add: function () {
        console.log('增加子菜单');
    },
    del: function () {
        console.log('删除子菜单');
    }
};
// 测试
bindClick(button1, MenuBar.refresh);
bindClick(button2, SubMenu.add); 
bindClick(button3, SubMenu.del);

7、组合模式:将对象组合成树形结构,以表示“部分-整体”的层次结构。

// 组合模式
var closeDoorCommand = {
    execute: function () {
        console.log('关门');
    }
};

var openPcCommand = { 
    execute: function () {
        console.log('开电脑'); 
    }
};
var openQQCommand = {
    execute: function () {
        console.log('登录 QQ');
    }
};

var MacroCommand = function () {
    return {
        commandsList: [],
        add: function (command) {
            this.commandsList.push(command);
        },
        execute: function () {
            for (var i = 0, command; command = this.commandsList[i++];) {
                command.execute();
            }
        }
    }
};
// 测试
var macroCommand = MacroCommand();
macroCommand.add(closeDoorCommand);
macroCommand.add(openPcCommand);
macroCommand.add(openQQCommand);

macroCommand.execute();

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值