JavaScript设计模式整理

逻辑沙漏
• 阅读 2083

写在前面

设计模式是程序员通识知识,熟练掌握并使用各种设计模式,可以体现一个程序员的工程开发水平。我花了几天时间,重温并整理了30多种设计模式,以JavaScript为示例语言。下面我会列出一些常用的设计模式说明及示例,更全面的内容见:https://github.com/yzsunlei/javascript-design-mode

什么是设计模式?

一个模式就是一个可重用的方案,可应用于在软件设计中的常见问题。另一种解释就是一个我们如何解决问题的模板 - 那些可以在许多不同的情况里使用的模板。

设计模式的分类:

创建型设计模式:
1、简单工厂模式
2、工厂方法模式
3、抽象工厂模式
4、建造者模式
5、原型模式
6、单例模式

结构型设计模式:
7、外观模式
8、适配器模式
9、代理模式
10、装饰者模式
11、桥接模式
12、组合模式
13、享元模式

行为型设计模式:
14、模板方法模式
15、观察者模式
16、状态模式
17、策略模式
18、职责链模式
19、命令模式
20、访问者模式
21、中介者模式
22、备忘录模式
23、迭代器模式
24、解释器模式

技巧型设计模式:
25、链模式
26、委托模式
27、数据访问对象模式
28、节流模式
29、简单模板模式
30、惰性模式
31、参与者模式
32、等待者模式

架构型设计模式:
33、同步模块模式
34、异步模块模式
35、Widget模式
36、MVC模式
37、MVP模式
38、MVVM模式

  • 备注:该分类借鉴于《JavaScript设计模式-张容铭》

工厂方法模式:

通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例。

// 安全模式创建的工厂类
var Factory = function(type, content) {
    if (this instanceof Factory) {
        // 保证是通过new进行创建的
        var s = new this[type](content);
        return s;
    } else {
        return new Factory(type, content);
    }
};

// 工厂原型中设置创建所有类型数据对象的基类
Factory.prototype = {
    Java: function(content) {

    },
    Php: function(content) {

    },
    JavaScript: function(content) {

    }
};

原型模式:

用原型实例指向创建对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。

// 图片轮播类
var LoopImages = function(imgArr, container) {
    this.imagesArray = imgArr;
    this.container = container;
};

LoopImages.prototype = {
    // 创建轮播图片
    createImage: function() {
        console.log("LoopImages createImage function");
    },
    // 切换下一张图片
    changeImage: function() {
        console.log("LoopImages changeImage function");
    }
};

// 上下滑动切换类
var SliderLoopImg = function(imgArr, container) {
    // 构造函数继承图片轮播类
    LoopImages.call(this, imgArr, container);
};
SliderLoopImg.prototype = new LoopImages();
// 重写继承的“切换下一张图片”方法
SliderLoopImg.prototype.changeImage = function() {
    console.log("SliderLoopImg changeImage function");
};

单例模式:

又称单体模式,是只允许实例化一次的对象类。

// 惰性
var LarySingle = (function() {
    // 单例实例引用
    var _instance = null;
    // 单例
    function Single() {
        // 这里定义私有属性和方法
        return {
            publicMethod: function() {},
            publicProperty: "1.0"
        };
    }
    // 获取单例对象接口
    return function() {
        // 如果未创建单例将创建单例
        if(!_instance){
            _instance = Single();
        }
        // 返回单例
        return _instance;
    };
})();

外观模式:

为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易。

function addEvent(dom, type, fn) {
    // 对于支持DOM2级事件处理程序addEventListener方法的浏览器
    if (dom.addEventListener) {
        dom.addEventListener(type, fn, false);
    } else if (dom.attachEvent) {
        // 对于不支持addEventListener方法但支持attchEvent方法的浏览器
        dom.attachEvent("on" + type, fn);
    } else {
        // 对于不支持addEventListener方法,也不支持attchEvent方法,但支持“on”+事件名的浏览器
        dom["on" + type] = fn;
    }
}

装饰者模式:

在不改变原对象的基础上,通过对其进行包装拓展(添加属性或方法)使原对象可以满足用户更复杂需求。

var decorator = function (input, fn) {
    // 获取事件源
    var input = document.getElementById(input);
    // 若事件源已经绑定事件
    if (typeof input.click === 'function') {
        // 缓存事件源原有回调函数
        var oldClickFn = input.click;
        // 为事件源定义新的事件
        input.click = function () {
            // 事件源原有回调函数
            oldClickFn();
            // 执行事件源新增回调函数
            fn();
        }
    } else {
        // 事件源未绑定事件,直接为事件源添加新增回调函数
        input.onclick = fn;
    }
}

观察者模式:

又称发布-订阅者模式或消息机制,定义一种依赖关系,解决了主体对象与观察者之间功能的耦合。

var Observer = (function () {
    var __messages = {};
    return {
        // 注册消息
        register: function (type, fn) {
            if (typeof __messages[type] === 'undefined') {
                __messages[type] = [fn];
            } else {
                __messages[type].push(fn);
            }
        },
        // 发布消息
        fire: function (type, args) {
            if (!__messages[type])
                return;
            var events = {
                type: type,
                args: args || {}
            };
            var i = 0;
            var len = __messages[type].length;
            for (; i < len; i++) {
                __messages[type][i].call(this, events);
            }
        },
        // 移除消息
        remove: function (type, fn) {
            if (__messages[type] instanceof Array) {
                var i = __messages[type].length - 1;
                for (; i >= 0; i--) {
                    __messages[type][i] == fn && __messages[type].splice(i, 1);
                }
            }
        }
    }
})();

状态模式:

当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。

// 状态对象
var ResultState = function () {
    var States = {
        state0: function () {
            console.log("第一种情况");
        },
        state1: function () {
            console.log("第二种情况");
        },
        state2: function () {
            console.log("第三种情况");
        },
        state3: function () {
            console.log("第四种情况");
        }
    };

    function show(result) {
        States['state' + result] && States['state' + result]();
    }

    return {
        show: show
    }
}();

命令模式:

将请求与实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数化。

// 绘图命令
var CanvasCommand = (function () {
   var canvas = document.getElementById('canvas');
   var ctx = canvas.getContext('2d');
   var Action = {
       fillStyle: function (c) {
           ctx.fillStyle = c;
       },
       fillRect: function (x, y, w, h) {
           ctx.fillRect(x, y, w, h);
       },
       strokeStyle: function (c) {
           ctx.strokeStyle = c;
       },
       strokeRect: function (x, y, w, h) {
           ctx.strokeRect(x, y, w, h);
       },
       fillText: function (text, x, y) {
           ctx.fillText(text, x, y);
       },
       beginPath: function () {
           ctx.beginPath();
       },
       moveTo: function (x, y) {
           ctx.moveTo(x, y);
       },
       lineTo: function (x, y) {
           ctx.lineTo(x, y);
       },
       arc: function (x, y, r, begin, end, dir) {
           ctx.arc(x, y ,r, begin, end, dir);
       },
       fill: function () {
           ctx.fill();
       },
       stroke: function () {
           ctx.stroke();
       }
   };
   return {
       excute: function (msg) {
           if (!msg)
               return;
           if (msg.length) {
               for (var i = 0, len = msg.length; i < len; i++) {
                   arguments.callee(msg[i]);
               }
           } else {
               msg.param = Object.prototype.toString.call(msg.param) === "[object Array]" ? msg.param : [msg.param];
               Action[msg.command].apply(Action, msg.param);
           }
       }
   }
})();

迭代器模式:

在不暴露对象内部结构的同时,可以顺序的访问聚合对象内部的元素。

// 迭代器
var Iterator = function (items, container) {
    var container = container && document.getElementById(container) || document;
    var items = container.getElementsByTagName(items);
    var len = items.length;
    var idx = 0;
    var splice = [].splice();

    return {
        first: function () {},
        second: function () {},
        pre: function () {},
        next: function () {},
        get: function () {},
        dealEach: function () {},
        dealItem: function () {},
        exclusive: function () {}
    }
};

链模式:

通过在对象方法中将当前对象返回,实现对同一个对象多个方法的链式调用。

var A = function (selector) {
    return new A.fn.init(selector);
};
A.fn = A.prototype = {
    constructor: A,
    init: function (selector) {
        console.log(this.constructor);
    }
};
A.fn.init.prototype = A.fn;

节流模式:

对重复的业务逻辑进行节流控制,执行最后一次操作并取消其他操作,以提高性能。

var throttle = function () {
    var isClear = arguments[0];
    var fn;
    if (typeof isClear === 'boolean') {
        fn = arguments[1];
        fn.__throttleID && clearTimeout(fn.__throttleID);
    } else {
        fn = isClear;
        param = arguments[1];
        var p = extend({
            context: null,
            args: [],
            time: 30
        }, param);
        arguments.callee(true, fn);
        fn.__throttleID = setTimeout(function () {
            fn.apply(p.context, p.args);
        }, p.time);
    }
}

参与者模式:

在特定的作用域中执行给定的函数,并将参数原封不动的传递。

// 函数绑定
function bind(fn, context) {
    return function () {
        return fn.apply(context, arguments);
    }
}

// 函数柯里化
function curry(fn) {
    var Slice = [].slice;
    var args = Slice.call(arguments, l);
    return function () {
        var addArgs = Slice.call(arguments);
        var allArgs = args.concat(addArgs);
        return fn.apply(null, allArgs);
    }
}

参考资料

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
徐小夕 徐小夕
4年前
《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。上期回顾《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
海军 海军
4年前
JavaScript设计模式之单例模式
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"fontsize:16px;color:black;lineheight:1.6;wordspacing:0px;letterspacing:0px;word
Wesley13 Wesley13
3年前
Java 设计模式(1)
设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种
Stella981 Stella981
3年前
JavaScript面向对象编程的15种设计模式
在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”。在JavaScript中并没有类这种概念,面向对象编程不是基于类,而是基于原型去面向对象编程,JS中的函数属于一等对象,而基于JS中闭包与弱类型等特性,在实现一些设计模式的方式上与众不同。ps:本文之讲述面向对象编程的设计模式策略,JavaScript原型的基础请参考阮一峰面向
Stella981 Stella981
3年前
Javascript中常用的13种设计模式
!(https://uploadimages.jianshu.io/upload_images/24944724cf8d19188586fa06.png?imageMogr2/autoorient/strip%7CimageView2/2/w/1240)介绍常用的Javascript设计模式。常用设计模式分类常用2
Wesley13 Wesley13
3年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Wesley13 Wesley13
3年前
Java描述设计模式(06):建造者模式
一、生活场景基于建造者模式,描述软件开发的流程。1、代码实现/基于建造者模式描述软件开发/publicclassC01_InScene{publicstaticvoidmain(Stringargs){B
工程中实践的微服务设计模式
最近在读《微服务架构设计模式》,开始的时候我非常的好奇,因为在我印象中,设计模式是常说的那23种设计模式,而微服务的设计模式又是什么呢?这个问题也留给大家,在文末我会附上我对这个问题的理解。本次文章的内容主要是工作中对微服务设计模式的应用,希望能对大家有所