在设计模式中,有着几条视为黄金原则,设计模式都是围绕黄金原则,对代码或者说是架构设计作出一些相应的调整,长此以往,GoF 4人组,发现其实有些设计思想能够称为模式,能实现代码复用的好处,从而设计模式出世。其实,这些模式的基石就是黄金原则,因此,接下来会对这些原则进行详细的解析。今天说一下,单一职责原则。ajax
单一职责原则,英文名叫作SRP.即,Single responsibility principle (装个逼). 咱们从字面上,差很少已经彻底能够理解这个原则所要表达的意思。在js中,函数永远是一等公民,而函数所表明的就是一份职责。 一个函数完成一个功能,最后编织成了咱们的js程序。设计模式
前面差很少把模式基本的梳理了一遍,要知道,每一个模式里面或多或少会包含一些原则。。。(我编不下去)缓存
说人话呀~~~ 俺们看不懂!!!
客官对不起,小的这就给你上栗子。安全
直接来干货。在代理模式中,你们还记得这个例子吗?图片的加载闭包
在未引入代理模式的时候是这样写的架构
var delayload = (function(){ var img = document.querySelector("#img"); img.src = "loading.gif"; var newImg = document.createElement("img"); newImg.onload = function(){ img.src = newImg.src; } return function(src){ newImg.src = src; } })(); delayload("jimmy.jpg");
咱们分析一下,在delayload里面存在了两个原则,一个是给本体的img设置src,还有一个是,虚拟构建一个Img节点来加载图片,最后在加载完成的时候,修改本体的src. 这样写,没错,若是在没有其余的需求以前,这个代码能够算是比较完美的。 可是,你的产经永远不会这么一心一意,有时候,会让你把,等待加载的图片换掉,有时候。。。app
因此为了扩展性考虑,咱们能够参考单一职责原则,修改以下:函数
//将背景图设置,和图片加载的src修改分开 var delayload = (function(){ var img = document.querySelector("#img"); return { setSrc:function(src){ img.src = src; } } })(); var proxy = (function(){ var img = document.createElement('img'); img.onload = function(){ delayload.setSrc(img.src); } return { setSrc:function(src){ delayload.setSrc("loading.gif"); img.src = src; } } })(); proxy.setSrc("jimmy.jpg");
这样一方面,对于本体img设置src的功能咱们能够完美的保留下来。this
相信你们都遇到这个问题,向后台请求数据,而后渲染到页面上。说具体一点就是,像这样的url
一本图书的信息,有他的img,title,author这3部份内容。 咱们的职责就是,向后台请求相关的数据,而后将数据渲染到页面。而咱们目前的职责就是两个,获取数据,而后渲染数据。
var data = { img:"http://7xpsmd.com1.z0.glb.clouddn.com/16-1-24/19756676.jpg", title:"JS权威指南", author:"David Flaagan" } http.getBooks = function(url,callback){ $.ajax(url) .then((data)=>{ itera(data,callback); }) } //要知道,这里的data可能不仅一个,咱们须要进行遍历 var itera = function(data,callback){ for(var i = 0,book;book = data[i++];){ callback(data); //渲染data } } //请求数据,而且渲染数据 http.getBooks("www.example.com",function(){ console.log("渲染数据"); });
简单流程是这样的,从大的方面来看,职责确实只有两个,可是咱们实现的时候,会发现,本体中嵌套一个for循环,会把添加节点函数带入,这样耦合性会增大,因此这里加了一个迭代器模式,让迭代器来表示循环,即,个人渲染函数只和迭代器发生关系,而你原来的ajax请求是怎么实现的我并不清楚。
能够看出,职责的划分不是一眼就能看出来的,那怎么看嘞?
其实,我也不知道,看感受呗,有时候感受来了,挡都挡不住.
上面已经说过了,SRP是在模式应用中,最简单的一个,一样也是应用最广的一个。回想一下,咱们在写单例的时候,一般的格式是一个闭包+一个变量就over了。
var Weather = function() {} var getSingle = (function() { var single; return function(obj) { if (single === undefined) { return single = obj; } return single; } })(); var weather1 = getSingle(new Weather()); //原始的Weather var weather2 = getSingle(new Weather()); //存储的single
这里,将单例类和获取单例的工厂分开来。 工厂能够无限制使用,单例类也能够执行他独特的行为。 这样作是极好的。 固然,咱们也能够创造不一样的工厂出来。
这个是缓存一个功能函数的结果,应用场景主要在加载额外的模板文件时,使用
var getSingle = function(fn){ var result; return function(){ return result || (result = fn.apply(this,arguments)); } }
AOP咱们应该算是阅人无数的级别了, 在不少地方都是用过他,职责链模式,装饰者模式等。而AOP也是完美体现SRP原则的。
首先,他自己的书写都是符合SRP原则
Function.prototype.before = function(fn){ var _this = this; return function(){ fn.apply(this,arguments); //值为Boolean,表示是否继续向下传递 return _this.apply(this,arguments); } }
将AOP的概念抽象化,而后就能够直接使用beofre。
一般咱们能够将AOP运用到,修改url参数,传递权限的业务上面。 好比,接口的地址原本已经很完美了,可是你的leader是处女座(最讨厌处女座),非要给url路由添加几个token以保证后台数据的安全。如今有两条路给你,要么直接改动路由,要么可使用AOP进行改动。 为了过年,我会选择使用AOP,由于不知道处女座之后会作出什么傻事来。
function dealUrl(url){ url+=param.getToken(); } http.ajax = http.ajax.before(dealUrl); http.ajax("www.example.com"); //此时的Url = www.example.com?token=23jkfd3kjfdksjfkjds
使用before动态织入后,能够完美的解决处女座。
实话说,我真的不知道。 我这里只有几条我认为比较好的经验给你们,由于若是过度追求设计的话,你的程序复杂度将会爆炸!!!。 在合适的时间,合适的位置使用,这才是SRP的难点。
说一下,不是用SRP原则的时候把。
分清行为和动做。 咱们只是用SRP区分动做,而不过度划分行为。行为就是: 建立div,添加类,修改attr等基本操做。 动做就是 将行为组合在一块儿达到的效果,好比发送请求,渲染节点。 这类比较抽象的动做。
要以第一感受为主,若是感受这样划分职责没错,使用SRP恰到好处,那就干吧。 反正之后自已挖的坑本身也得补回来,要知道,没有重构过的代码,永远是不能看的(说的是我。。。)。
其实有时候,从正面走不行,咱们能够尝试一下逆向思惟,想一想,你日常没有使用SRP原则是何时就能够了。这样可以帮助你思惟的发展,也能让你写出一手好代码。