实用的设计模式1——单例模式

news/2024/7/3 6:49:14

在软件工程中,设计模式( 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);
    } 
};

http://www.niftyadmin.cn/n/2606774.html

相关文章

一条502报警引发的胡思乱想

安心倒计时 忙完了今天的工作, 终于到了周五,可以好好休息下了。 睡梦惊醒 就在安心养神的时候, 同事转给了我一条nginx 502的报警, 赶紧去线上一顿排查。 首先得先找出哪台机器报出的(同时喊运维看下线上负载情况), 发现01机器的nginx日志在报警时间点的错误信息: *272881176 …

工作一年了的心得体会

工作至今有一年的时间了,这一年有过开心,也有失落。但是回首看看,似乎更多的是迷茫。 刚来公司的时候,打心底想好好学一学技术,学一点有用的东西。但是进公司之后发现很多和自己想的不太一样。来到了一个做监控平台的组…

Zookeeper学习(一) 概述

0. 前言 前段时间在工作中参与了一个分布式项目的开发,其中一个重要的模块就是Zookeeper。可以说这个项目及其之后的一段学习让我找到了自己的兴趣点,自己最近也学习了一些Zookeeper的知识,在这里也把自己学到的和一些思考写下来~ 1. 分布式协…

[转]React Native 语言基础之ES6

React Native 是基于 React 这个前端框架来构建native app的架构。React Native基于ES6(即ECMAScript2015)语言进行开发的。 JS的组成 1) 核心(ECMAScript):描述了该语言的语法和基本对象。担当的是一个翻译的角色&am…

canvas 实现vue 手势解锁组件

1.手机锁屏九宫格解锁组件 2.代码如下 <template><canvas id"gesture" ref"canvas" :style"style" /></template><script>export default {name: GestureLock,props: {chooseType: {type: Number,default: 3 // 3: 3*3,…

Scala - 快速学习06 - 面向对象

1- 类 1.1- 简介&#xff1a;类、方法及对象 类是用来创建对象的蓝图。Scala文件中包含的多个类之间&#xff0c;都是彼此可见的&#xff0c;不需要声明为public。创建对象定义好类以后&#xff0c;就可以使用new关键字来创建对象。字段默认为public&#xff0c;在类外部和内部…

设计模式-创建型模式-建造者模式

设计模式-创建型模式-建造者模式建造者模式即生成器模式&#xff0c;将一个复杂的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 代码如下 // 产品类 public class Product{public void doSomething(){// 业务处理} } // 抽象建造者 public abstract …

redis 系列18 事件

一.概述 Redis服务器是一个事件驱动程序&#xff0c;服务器需要处理两类事件&#xff1a;1文件事件&#xff0c;2时间事件。文件事件是关于客户端与服务器之间的通信操作。时间事件是关于服务器内部的一些定时操作。本篇还是参照"Redis设计与实现"书&#xff0c;简要…