js设计模式

js的设计模式增强我们代码结构的强度,可维护性更好,可复用性也更强。

单例模式

单例模式就是保证一个类只有一个实例,实现的方法是先判断实例时候存在,如果存在那么就直接返回实例,否则创建实例。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//例子1
//创建xiaowan和xiaomin,xiaowan想通过门铃呼叫xiaomin,那么就要先判断门门铃时候存在吗,不存在就创建,存在就直接按门铃
var xiaomin=(function(){
var xiaominjia=func(msg){
this.melling=msg;
}
var men;
var info={
sendMes:function(){
if(!men){
men=new xiaominjia();
}
return men;
}
}
return info;
})()
var xiaowan={
callXiaomin:function(msg){
var a=xiaomin.sendMes(msg);
console.log(a.melling);
a=null;//垃圾回收机制
}
}

//例子2(实际项目)
//一个页面有很多点击事件,而且每个点击事件可能会需要用到上一个点击事件的数据等,那么我们可以将点击事件封装成一个独立的对象
var top={
init:function(){
this.render();
this.bind();
},
a:4,
//获取点击事件的元素
render:function(){
that=this;
that.btn=$("#a");
},
//绑定点击事件
bind:function(){
that=this;
that.btn.onclick=function(){
that.test();
}
},
//点击触发的事件
test:function(){
a=9;
}
}
top.init();

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//情景:点击按钮创建元素,弹出弹框
// 实现弹窗
var createWindow = function(){
var div = document.createElement("div");
div.innerHTML = "我是弹窗内容";
div.style.display = 'none';
document.body.appendChild('div');
return div;
};
document.getElementById("Id").onclick = function(){
// 点击后先创建一个div元素
var win = createWindow();
win.style.display = "block";
}
//如上的代码;大家可以看看,有明显的缺点,比如我点击一个元素需要创建一个div,我点击第二个元素又会创建一次div,我们频繁的点击某某元素,他们会频繁的创建div的元素,虽然当我们点击关闭的时候可以移除弹出代码,但是呢我们频繁的创建和删除并不好,特别对于性能会有很大的影响,对DOM频繁的操作会引起重绘等,从而影响性能;因此这是非常不好的习惯;我们现在可以使用单体模式来实现弹窗效果,我们只实例化一次就可以了;如下代码:
// 实现单体模式弹窗
var createWindow = (function(){
var div;
return function(){
if(!div) {
div = document.createElement("div");
div.innerHTML = "我是弹窗内容";
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
})();
document.getElementById("Id").onclick = function(){
// 点击后先创建一个div元素
var win = createWindow();
win.style.display = "block";
}
//上面的弹窗的代码虽然完成了使用单体模式创建弹窗效果,但是代码并不通用,比如上面是完成弹窗的代码,假如我们以后需要在页面中一个iframe呢?我们是不是需要重新写一套创建iframe的代码呢,所以就得用一套可以复用的代码来实现,代码如下:

//[----------完整版-------------]
// 创建div
var createWindow = function(){
var div = document.createElement("div");
div.innerHTML = "我是弹窗内容";
div.style.display = 'none';
document.body.appendChild(div);
return div;
};
// 创建iframe
var createIframe = function(){
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
return iframe;
};
// 获取实例的封装代码
var getInstance = function(fn) {
var result;
return function(){
return result || (result = fn.call(this,arguments));
}
};
// 测试创建div
var createSingleDiv = getInstance(createWindow);
document.getElementById("Id").onclick = function(){
var win = createSingleDiv();
win.style.display = "block";
};
// 测试创建iframe
var createSingleIframe = getInstance(createIframe);
document.getElementById("Id").onclick = function(){
var win = createSingleIframe();
win.src = "http://cnblogs.com";
};

构造函数模式

构造出特定类型的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//情景:小明和小王的房门有不一样的门的款式,那么我们就可以传递参数给制造商
function zaomen(huawen){
if(!(this instanceof zaomen )){
return new zaomen();
}
 this.suo="普通";
 var _huawen="普通";
if(huawen){
_huawen=huawen;
}
 this.huawen=_huawen;
this.create=function(){
   return "【锁头】"+this.suo+"【花纹】"+this.huawen;
}
}
var a=new zaomen();
console.log(a.create());
var b=new zaomen();
console.log(b.create("酷炫的门"));

建造者模式

将一个复杂的对象与表示分离,简单点讲就是我只要提出我的要求具体的事情怎么做我不要管

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
//情景白富美想盖房子,找到包工头,包工头再找工人造房子
function fanzhi(){
this.chufan="";
this.ketin="";
this.toilet="";
}
function baogongtou(){
this.gaifangzhi=function(){

}
}
funtcion gongren(){
this._gaichufan=function(){
console.log("厨房改好了");
}
this._gaiketin=function(){
console.log("客厅盖好了");
}
this._gaitoilet=function(){
console.log("厕所盖好了");
}
//交付房子
this.jiafangzhi=function(){
var newfanzhi=new fanzhi();
newfanzhi.chufan="ok";
newfanzhi.ketin="ok";
newfanzhi.toilet="ok";
}
}
var gonren_work=new gongren();
var baogontou_order=new baogongtou();
baogontou_order.gaifagnzhi(gongren);//包工头发出指令

工厂模式

简单点讲就是解决多个相似的问题,工厂下还有对应的子类,比如一家工厂他下面还有生产衣服的子公司和生产鞋子的子公司,实际开发中我们用的也比较多,比如jquery中的$.ajax(url:’a.php’),a.php就是我这个厂长发出要制造的东西的指令,$.ajax这个方法就是工厂,他负责把这个指令传达给下面的子公司去完成,这里的子公司就是jquery后台代码封装的一些处理方法,也就是做具体的工作
缺点:不能知道对象识别的问题

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
36
37
38
39
40
//简单的工厂
var factory=function(){

}
factory.createXMLHttp=function(){
var xmlhttp=null;
if(window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}else if(window.ActiveObject){
xmlhttp=new ActiveObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
var hander=function(){
var xmlhttp=factory.createXMLHttp();//具体的操作
}
}

//复杂的工厂
var xmlFactory=function(){

}
xmlFactory.prototype=function(){
 //这个工厂是其他子工厂的总部,负责分工,不负责制造
throw new Error('这不是我的工作');
}
var childFactory=function(){
xmlFactory.call(this);
}
childFactory.prototype=new xmlFactory();//覆盖父厂的方法,这才是我的本职工作
childFactory.prototype.constructor=childFactory;
childFactory.prototype=function(){
// 这里面才是我真正工作的地方
if(window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}else if(window.ActiveObject){
xmlhttp=new ActiveObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}

代理模式

简单点讲就是通过中介替我们做事

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
36
//代理模式需要三方
//买家
function maijia(){
 this.namme="小明";
}
//中介
function zhonjie(){}
zhonjie.prototype.maifan=function(){
 new fandong(new maijia()).maifan("20万");
}
function fandong(){
this.maijia_name=maijia.name;
this.maifan=function(money){
console.log('收到了来自'+this.maijia_name)
}
}
(new zhongjie).maifan();

//例子2
var naicha=function(name){
this.name=name;
}
var ceo=function(girl){
this.girl=girl;
this.sendRing=function(ring){
  console.log("我要送个"+ring+"给"+this.girl);
}
}
var zhuli=function(girl){
this.girl=girl;
this.sendGift=function(gift){
new ceo(this.girl).sendRing(gift);
}
}
var proxy=new zhuli(new naicha("奶茶妹"));
proxy.sendGift("钻石");

命令模式

用来对方法调用进行参数化的处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行,比如司令发布一个作战指令给连长,连长发布命令给小分队,然后上级可以先将一二分队先上,三四分队后上这就是参数化的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var lian={}
   //炮兵
   lian.paobin=function(pao_num){
  console.log(pao_num+"炮"+"开始战斗");
}
   //步兵出动人数
   lian.bubin=function(bubin_num){
  console.log(bubin_num+"人")
}
   //连长接收命令
   lian.lianzhan=function(minlin){
lian[minlin.type](minlin.num);
}
   //司令发出作战指令
lian.lianzhan({
  type:"bubin",
num:200
})

观察者模式

也叫作订阅者模式,定义了一种一对多的关系,多个观察者同时监听某个主题对象,当主题对象发生改变的时候,多个观察者都会收到信息

适配器模式

将一个类(对象)的接口(方法和属性)转化才能成客户希望的另外的一种接口

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
//原本是这样写的
var a={
test:unction(){},
go:function(){}
}
//调用
a.test()
//上面这样的写就是一个静态的object了,如果我加入一个对象里面存在同名的属性就会覆盖原有的属性
//重构成下面这样子的
function a(){
this.test=function(){
console.log("这是新的test");
}
}
a.prototype.gogo=function(){
console.log("这是新的gogo");
}
//如果像之前a.test()这样访问的是不行的,所以就得需要一个适配器来解决重构对自己的代码带来的影响
function filter(){
var newA=new a();
var a={
test:function(){
newA.test();
},
go:function(){
newA.gogo();
}
}
return a;
}
var a=filter();
a.test();//这样就可以像之前那样访问了

职责链模式

使多个对象有机会同时处理请求,避免发送者和接受者的耦合关系,将这个对象形成一条链,沿着这条链,直到有一个对象处理他为止

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
//给老板一个写代码的任务,老板不会就交给了项目经理,项目经理不会就交给了程序狗
function laoban(xianmujinli){
if(xianmujinli){
  this.xianmujinli=xianmujinli;//把项目经理写代码的能力赋予自己
  }
}
laoban.prototype.write=function(php){
this.xianmujinli.write(php)
}
function xianmujinli(corder){
if(corder){
this.corder=corder;
}
}
xianmujinli.prototype.write=function(php){
this.corder.write(php);
}
function corder(php){

}
corder.prototype.write=function(php){
 console.log("cord....."+php);
}
var begin=new laoban(new xianmujinli(new corder()))
begin.write('php');

参考资料:地址1 | 地址2
作者:陈焦滨#kevin

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器