摘要:模式迭代器模式顾名思义,迭代器可以将对于一个聚合对象内部元素的访问与业务逻辑分离开。模式组合模式组合模式将对象组合成树形结构,以表示层级结构。重点是,叶结点与中间结点有统一借口。本文总结自设计模式与开发实践,曾探著
模式1 - 单例模式
单例模式的核心是确保只有一个实例,并且提供全局访问。
特点:
满足“单一职责原则” : 使用代理模式,不在构造函数中判断是否已经创建过该单例;
满足惰性原则
应用:
弹出登陆窗口。
实例:
var getSingle = function (fn) { var res; return function() { return res || (res = fn.apply(this, arguments)); } } var createPopup() { var div = document.createElement("div"); div.innerHTML = "Login window"; div.style.display = "none"; document.body.appendChild(div); return div; } var createLoginPopup = getSingle(createPopup); //create popup div here by using a given function, 满足两个原则 document.getElementById("loginBt").onclick = function() { var popup = createLoginPopup(); pop.style.display = "block"; }
模式2 - 策略模式
定义一个个可以相互替换的算法,并且把他们封装起来。
特点:
符合开放-封闭原则 : 要修改使用的算法时不用深入函数内部进行修改,只需修改策略类;
将算法的实现与使用分离开,提高算法复用性;
通过组合、委托和多态避免多重条件选择语句;
应用:
动画实现不同的缓动效果。
一般分为两个部分:策略类于环境类。策略类用于封装各种算法,并且负责具体的计算过程; 环境类负责接收用户的请求,并且把请求委托给某一个策略类。因为各个策略类实现的算法和计算的结果不同,而环境类调用策略类的方法却是相同的,这就体现了多态性。要想实现不同的算法,只需要替换环境类中的策略类即可。
在js中,我们不必构造策略类,可直接使用函数作为策略对象。
示例:
var strategies = { "s1": function() { //algo 1 }, "s2": function() { //algo 2 }, "s3": function() { //algo 3 } } var someContext = new SomeConext(); someContext.start("s1"); //using s1 to calculate //someContext.add("s1"); or add s1 as a rule for validation
模式3 - 代理模式
代理就像一个经纪人,当用户不方便直接访问某个对象或者需要对访问进行一些过滤/加工时,可以通过代理来进行对象访问。代理会对请求进行一些处理,然后再将请求传递给本体。
一般分为保护代理和虚拟代理:
保护代理负责过滤掉一些请求;
虚拟代理则是将一些花销比较大的操作延迟到真正他的时候再去创建,例如new一个对象。
特点:
保证对象符合单一职责原则;
应用:
图片预加载, 合并http请求, 惰性加载, 缓存代理(避免重复计算,可以写一个通用的缓存对象(其实就是一个闭包),将高阶函数作为参数传入)。
模式4 - 迭代器模式
顾名思义,迭代器可以将对于一个聚合对象内部元素的访问与业务逻辑分离开。
一般分为内部迭代器和外部迭代器:
内部迭代器只需一次初始调用,不需要关心迭代器的内部实现;
外部迭代器需要显式地请求下一个元素,因此可以手工控制迭代过程和顺序,例如调用iterator.next();
无论是哪种迭代器,只要聚合对象有length属性并且可以通过下标访问,那么就可以被迭代。因此类数组对象及字面量对象(用for in)都可以。
绝大部分语言都内置了迭代器。
应用:
可以通过添加终止条件来中断迭代:在callback函数中判断,如果return值为false,则通过break跳出迭代循环。
由此可以设计根据浏览器类型创建的返回对象,按优先级一个个迭代。
模式5 - 订阅发布模式
将许多对象弱耦合起来,当一个对象的状态发生变化时,所有订阅了该变化的对象都会收到通知。
DOM事件是典型的订阅发布模式,同时我们还可以自定义事件:
var event = { clients : {}, listen : function (signal,fn){ if(!this.clients[signal]) { this.clients[signal] = []; } this.clients[signal].push(fn); }, trigger: function (arguments){ //not only trigger the event, but also send some data var sig = Array.prototype.shift.call(arguments); fns = this.clients[sig]; if(!fns || fns.length === 0) return false; for(var i = 0; i < fns.length; i++) { var fn = fns[i]; fn.apply(this, arguments); } }, remove: function (signal,fn){ var fns = this.clients[signal]; if(!fns) return false; if(!fn) { //remove all fns delete this.clients[signal]; } else { for(var i = 0; i可以通过离线消息栈来保存没有被订阅的但是发生了的事件,等到有人订阅再依次取出执行。
应用:
网站登录-当用户登录成功并且ajax返回数据后,trigger事件,需要用到用户数据的渲染模块订阅该事件。模式6-命令模式
可以解决请求发送者和请求接受者之间的耦合关系。实际上,我们只需要调用command对象中的execute方法就行,他会自动调用命令接收者对应的命令。
示例:
var tv = { open: function() { console.log("open tv"); }, close: function() { console.log("turn off tv"); }, nextChannel: function() { console.log("next channel"); } } //相当于我把receiver的一些可用操作封装到command对象里了,并且提供了统一的接口 var openTVCmd = function(receiver) { return { execute: function(){ receiver.open(); }, undo : function() { //go to previous channel } } } var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var setCmd = function(button, cmd) { button.onclick = function(){ cmd.execute(); } } var opentvcmd = new openTVCmd(); setCmd(btn1, opentvcmd); btn2.onclick = function(){ //undo command opentvcmd.undo(); }应用:
可实现命令的撤销和重做,只需纪录一个oldState或者使用一个缓存来存放历史命令;
可实现命令队列,将command对象压入堆栈,只需依次调用他们的execute函数,由此可实现宏命令;
可分为智能命令和傻瓜命令:
1.智能命令不需要知道receiver,可自己完成请求,代码上类似策略模式,但目的不同;
2.傻瓜命令则只负责将请求传递给真正的receiver。模式7-组合模式
组合模式将对象组合成树形结构,以表示层级结构。借助于对象的多态性,它使得用户可以统一地对待组合对象(单个对象的组合)和单个对象。
应用:
可实现宏命令,只需要调用根结点的execute,程序会自动遍历整棵树并依次执行各中间节点和叶结点的execute函数。重点是,叶结点与中间结点有统一借口。
可用来模拟文件和文件夹层级结构:
示例:
var Folder = function(name) { this.name = name; this.files = []; } Folder.prototype.add = function(file) { this.files.push(file); } Folder.prototype.scan = function() { console.log("begin scanning folder "+ this.name); for(var i=0; i注意,层级1与层级2结点之间并非父子关系,只是因为他们有统一的借口而被联系在一起。
可以对这两种结点建立双向映射,即使文件1里面含有其父结点的引用,这样子在删除一个文件时就需要将其在其父结点的files中删除。组合模式使得用户可以忽略组合对象和单个对象的差异而统一对待,但这也会使得每个对象看上去都差不多,增加代码理解的难度。
P.s. 本文总结自《JavaScript设计模式与开发实践》,曾探著
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/91264.html
摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...
摘要:首先,需要来理清一些基础的计算机编程概念编程哲学与设计模式计算机编程理念源自于对现实抽象的哲学思考,面向对象编程是其一种思维方式,与它并驾齐驱的是另外两种思路过程式和函数式编程。 JavaScript 中的原型机制一直以来都被众多开发者(包括本人)低估甚至忽视了,这是因为绝大多数人没有想要深刻理解这个机制的内涵,以及越来越多的开发者缺乏计算机编程相关的基础知识。对于这样的开发者来说 J...
摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...
摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。背后的故事本文是对于年之间世界发生的大事件的详细介绍,阐述了从提出到角力到流产的前世今生。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎...
摘要:是文档的一种表示结构。这些任务大部分都是基于它。这个实践的重点是把你在前端练级攻略第部分中学到的一些东西和结合起来。一旦你进入框架部分,你将更好地理解并使用它们。到目前为止,你一直在使用进行操作。它是在前端系统像今天这样复杂之前编写的。 本文是 前端练级攻略 第二部分,第一部分请看下面: 前端练级攻略(第一部分) 在第二部分,我们将重点学习 JavaScript 作为一种独立的语言,如...
摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...
阅读 369·2023-04-25 16:38
阅读 1482·2021-09-26 09:46
阅读 3326·2021-09-08 09:35
阅读 2778·2019-08-30 12:54
阅读 3248·2019-08-29 17:06
阅读 1017·2019-08-29 14:06
阅读 3344·2019-08-29 13:00
阅读 3466·2019-08-28 17:53