javaScript设计模式-创建型设计模式
我们大家一听到设计模式就感觉设计模式是一个高端的东西,到底什么是设计模式呢?其实设计模式也就是我们的前辈在写代码的时候遇到的问题,提出的解决方案,为了方便人与人之间的交流,取了个名字,叫做设计模式。
创建型设计模式
本文今天主要写一部分创建型设计模式,创建型设计模式呢就是我门创建对象的时候的一种模式。废话不多说了,直接上代码和解释吧。
单例模式
目的:单例模式的目的是为了解决全局命名空间污染,冲突。
1 function g(id) { 2 return document.getElementById(id); 3 } 4 5 function css(id,key,value) { 6 g(id).style[key] = value; 7 } 8 9 function html(id,value) { 10 g(id).innerHTML = value; 11 } 12 13 function on(id,type,fn) { 14 g(id)['on'+type] = fn; 15 }
上面的代码在页面中添加了许多的变量,日后其他的人要为页面添加新的需求时,增加代码或者是重写了代码,比如这个on方法,那么就会和其他人的代码冲突,所以可以用单例模式来书写一下代码。
代码样式如下
1 //工程师 z 2 var xiaoz = { 3 g : function (id) { 4 return document.getElementById(id); 5 }, 6 css : function (id,key,value) { 7 g(id).style[key] = value; 8 } 9 }; 10 //工程师 y 11 var xiaoy = { 12 css : function () { 13 //一堆代码 14 } 15 };
这样几个人之间的代码就不会相互影响了,上面的代码调用的方式如下。
1 xiaoz.g('box');
在单例模式中还有另外一种,关于静态变量在es6才提出来的const,静态变量是一旦确定就无法修改的量,但是现在es6的兼容性还不是太好,在单例模式中同样可以模拟这种可以定义但是无法改变的变量。
1 var xiao = (function(){ 2 var bian = { 3 a : 1, 4 b : 2, 5 fn : function(){ 6 console.log('这里是fn') 7 } 8 }; 9 return { 10 getdata:function(val){ 11 return bian[val]; 12 } 13 } 14 })(); 15 //里面的变量只能获取 不能修改
简单工厂模式
简单工厂模式不是解决命名空间问题的,是为了解决创建对象的。
看下面的代码例子
//牛排 function Steak(){ this.price = 30; this.time = 20; } //炒饭 function FriedRice(){ this.price = 10; this.time = 5; } //面条 function Noodles(){ this.price = 15; this.time = 10; } var a = new Steak(); var b = new FriedRice(); var c = new Noodles(); //归类 开了个饭店a卖牛排 又开了个饭店b 卖炒饭 //开一家就可以了
上面的代码就相当于我们开饭店,我们开了一家卖牛排的店,又开了一家卖炒饭的店,然后又开了一家卖面条的店,虽然我们比较有钱,但是其实开一家店卖这几样东西就可以了
所以我们归类,看下面的代码就是简单工厂模式
1 function Shop(name){ 2 var o = null; 3 switch(name){ 4 case 'Steak' : 5 o = new Steak(); 6 break; 7 case 'FriedRice' : 8 o = new FriedRice(); 9 break; 10 case 'Noodles' : 11 o = new Noodles(); 12 break; 13 } 14 return o; 15 } 16 17 new Shop('Noodles'); 18 //好处 比如手机里面有很多软件 软件归类 好找 不用记什么是什么了 19 20 //缺点 这个拓展有点不好
至于说缺点拓展性不好的理由呢就是,比如我们又要开一家烤鸭店的话,我们不仅要定义一个烤鸭的构造函数,而且还要在工厂中增加一个判断,这个我就不写了,下面看看工厂模式就解决了这个问题
工厂模式
1 function Shop(name) { 2 console.log(this); 3 return new this[name](); 4 } 5 6 7 Shop.prototype = { 8 Steak : function () { 9 this.price = 30; 10 this.time = 20; 11 }, 12 FriedRice : function () { 13 this.price = 30; 14 this.time = 20; 15 }, 16 Noodles : function () { 17 this.price = 30; 18 this.time = 20; 19 } 20 }; 21 22 var obj = new Shop('FriedRice'); 23 24 console.log(obj);
上面的如果在拓展的话直接在原型上拓展就可以了,非常方便。也非常好用。
原型模式
原型模式是为了解决....
好了先不说解决什么,我们来几个需求
比如说我们需要写一个轮播图,我们就开始写了,样式就不写了哈。
<div>
<ul>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
</ul>
</div>
1 var oUl = document.getElementsByTagName('ul')[0]; 2 aLi = document.getElementsByTagName('li'); 3 4 var index = 0, 5 len = aLi.length; 6 7 function Fn() { 8 oUl.style.left = 600*index; 9 index %= len; 10 index++; 11 } 12 13 setInterval(Fn,1000);
应该是可以实现的吧,没有实验,如果有错误指正一下。有问题又来了,如果又有一个新的轮播图需要在轮播图上面添加上两个前进后退按钮,那么你会怎么做,你可能会想反正代码也不多我直接拿过来复制,在添加几行代码不就完了吗,是这样的没错,可是你想想如果有好多的轮播特效,你是不是每一种特效都需要复制一下上面的代码呢,他们都是重复的,所以我们可以用原型模式把上面的代码来继承下来。
1 var oUl = document.getElementsByTagName('ul')[0], 2 aLi = document.getElementsByTagName('li'), 3 div = document.querySelector('div'); 4 5 var index = 0; 6 7 //基本滚动 8 function Banner(div){ 9 this.dom = div; 10 this.init(); 11 } 12 //原型 13 Banner.prototype.init = function(){ 14 var oUl = this.dom.getElementsByTagName('ul')[0]; 15 var aLi = oUl.getElementsByTagName('li'), 16 len = aLi.length; 17 setInterval(function () { 18 oUl.style.left = 600*index; 19 index %= len; 20 index++; 21 },1000) 22 }; 23 24 // 那么这个时候只需要继承过来 然后再这基础之上进行扩展 简单点就是原型继承 25 function F() {} 26 F.prototype = Banner.prototype; 27 28 function Banner2(dom) { 29 Banner.call(this,dom); 30 this.goudan(); 31 } 32 Banner2.prototype = new F(); 33 Banner2.prototype.Slide = function () { 34 console.log('滚动'); 35 }; 36 37 new Banner2(div);
代码可能不是那么严谨,这里你知道大概的目的是什么就可以了,你还可以在他的原型上面拓展出来好多其他特效,当然这种模式不仅仅应用于轮播图特效,是为了代码的复用问题。
建造者模式
比如我们在工作需求中,需求经常发生变动,有时候一些变化可能会引起许多代码的修改,这时我们的解决方案出来了,可以把一个对象分步骤建造出来,实现的功能分步骤单例出来。看一下下面的小例子
发布简历
1 //简历 : 人,姓名,职位 2 var Human = function(param){ 3 //技能 4 this.name = param || '保密'; 5 }; 6 Human.prototype.getname = function(){ 7 return this.name; 8 }; 9 var Work = function(work){ 10 switch(work){ 11 case 'code': 12 this.work = '工程师'; 13 this.workDescript = '每天沉迷于编程'; 14 break; 15 case 'UI': 16 this.work = '设计师'; 17 this.workDescript = '设计是一种态度'; 18 break; 19 case 'teach': 20 this.work = '教师'; 21 this.workDescript = '分享也是一种态度'; 22 break; 23 default: 24 this.work = work; 25 this.workDescript = '对不起我们还不清楚你的职位描述'; 26 } 27 }; 28 29 //最终创建的对象 30 var Person = function(skill,work){ 31 var _Person = new Human(skill); 32 _Person.work = new Work(work); 33 return _Person; 34 }; 35 //这样就可以 36 Person('xiaoz',teach);
前面几种工厂模式,他们都有一个共同的特点,就是创建的结果都是一个完整的个体,对创建的过程不得而知,我们只知道得到的创建结果,而在建造者模式当中,我们关心的是对象的创建过程,因为我们通常将创建对象的类模块化,这样使被创建的类的每一个模块都可以得到灵活的额运用与高质量的复用,在这个过程中我们又组合成一个完整的个体。
这种方式对于整体对象又变得复杂了一些,所以如果对象很小,我们最好还是创建整体对象。
如果你阅读了本文章有了一些收获,我会感到非常开心,由于能力有限,文章有的部分解释的不到位,希望在以后的日子里能慢慢提高自己能力,如果不足之处,还望指正。
在接下来的时间,我还会把其他的一些常用的设计模式分享给大家,希望可以支持一下。