在软件工程中,设计模式( design pattern )是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。

看维基上对设计模式的定义,你就知道设计模式的重要性,但是往往编程中设计模式要不就是感觉高深莫测要不就是热衷于概念,所以写这个系列的文章,主要谈谈怎么把设计模式真正的用到平时的编程中,希望对大家有帮助。

单例模式

下面是一个创建登录框的例子:

var createLoginLayer = function(){
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    div.style.display = 'none'; 
    document.body.appendChild( div );
    return div;
};

document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createLoginLayer(); 
    loginLayer.style.display = 'block';
};

这里有个问题就是如果这个登录框已经存在的情况下,就不应该再创建了,修改下代码:

var loginLayer = null;
var createLoginLayer = function(){
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    div.style.display = 'none'; 
    document.body.appendChild( div );
    return div;
};

document.getElementById( 'loginBtn' ).onclick = function(){ 
    loginLayer = loginLayer || createLoginLayer(); 
    loginLayer.style.display = 'block';
};

我们用一个全局变量储存了生成的layer,如果不存在再去创建它。我们把单例的条件改复杂点,比如我们这段程序需要在多个页面用到,但是每个页面都有自己的登录框,现在修改下程序

var loginLayer = null;
var createLoginLayer = function(title){
    var div = document.createElement( 'div' );
    div.innerHTML = title;
    div.style.display = 'none'; 
    document.body.appendChild( div );
    return div;
};
var loginHandle = function(title) {
    loginLayer = loginLayer || createLoginLayer(title); 
    loginLayer.style.display = 'block';
}
var addLoginHandle = function(id, title) {
    document.getElementById( id ).onclick = function(){ 
        loginHandle(title)
    };
}
// 主页的登陆按钮
addLoginHandle('mainLoginBtn', '主页');
// 这是帮助页的登陆按钮
addLoginHandle('helpLoginBtn', '帮助中心'');

你发现了吗,如果在主页中先点击登陆按钮,然后在帮助页面点登陆按钮就不会重新创建登录页了,我们再改下程序

var loginLayer = null;
var createLoginLayer = function(title){
    var div = document.createElement( 'div' );
    div.innerHTML = title;
    div.style.display = 'none'; 
    document.body.appendChild( div );
    return div;
};
var loginHandle = function(title) {
    if(!loginLayer || loginLayer.innerHTML !== title) {
        loginLayer = createLoginLayer(title); 
    }   
    loginLayer.style.display = 'block';
}
var addLoginHandle = function(id, title) {
    document.getElementById( id ).onclick = function(){ 
        loginHandle(title)
    };
}
// 主页的登陆按钮
addLoginHandle('mainLoginBtn', '主页');
// 这是帮助页的登陆按钮
addLoginHandle('helpLoginBtn', '帮助中心'');

到此一个普通的单例其实就已经结束了,但这并不是本文最重点的地方,再看一看设计模式的定义:软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。我们的主要目的是把程序中公用的能普遍适用的地方提取出来:

var getSingle = function( fn, getNewSingle ){
    var result;
    return function(){
        return ((getNewSingle && getNewSingle(result)) || (!getNewSingle && result) || ( result = fn.apply(this, arguments);
    } 
};
var createLoginLayer = function(title){
    var div = document.createElement( 'div' );
    div.innerHTML = title;
    div.style.display = 'none'; 
    document.body.appendChild( div );
    return div;
};
var loginHandle = function(title) {
    var loginLayer = getSingle(createLoginLayer, function(layer){
        return layer.innerHTML === title;
    }); 
    loginLayer.style.display = 'block';
}
var addLoginHandle = function(id, title) {
    document.getElementById( id ).onclick = function(){ 
        loginHandle(title)
    };
}
// 主页的登陆按钮
addLoginHandle('mainLoginBtn', '主页');
// 这是帮助页的登陆按钮
addLoginHandle('helpLoginBtn', '帮助中心'');

你可以看到 getSingle 这个函数就是我们用来实现单例模式的函数,一方面提取了一个公用的函数,让思路更清晰;另一方面用闭包的形式减少了一个全局变量。

总结: 写到最后,其实单例模式在js中就是一个高阶函数,把这个函数记住然后会用,单例就基本掌握了。
// 如果没传getNewSingle,就生成普通的单例就行了,否则根据条件生成(根据属性生成多个单例的情况)
var getSingle = function( fn, getNewSingle ){
    var result;
    return function(){
        return ((getNewSingle && getNewSingle(result)) || (!getNewSingle && result) || ( result = fn.apply(this, arguments);
    } 
};

hk
680 声望111 粉丝

不断学习,等待时间的回报!