设计模式了解应用,发布订阅模式,单例模式
- 模式是经历了:大量实际项目验证的优秀的解决方案
适配器
小到参数格式的处理,大到(两个实现方式不同但相同功能的)类的方法,提供一个的类名一样的接口
百度、google 提供一个 show 方法
js
var googleMap = {
show: function () {
console.log("开始渲染谷歌地图");
},
};
var baiduMap = {
display: function () {
console.log("开始渲染百度地图");
},
};
var baiduMapAdapter = {
show: function () {
return baiduMap.display();
},
};
renderMap(googleMap);
renderMap(baiduMapAdapter);
策略模式
js
var strategies = {
"S": function( salary ){
return salary * 4;
},
"A": function( salary ){
return salary * 3;
},
"B": function( salary ){
return salary * 2; }
};
}
var calculateBonus = function( level, salary ){
return strategies[ level ]( salary ); // 多态在策略模式中的体现:当我 们对这些策略对象发出“计算奖金”的请求时,它们会返回各自不同的计算结果,
};
console.log( calculateBonus( 'S', 20000 ) ); // 输出:80000
console.log( calculateBonus( 'A', 10000 ) ); // 输出:30000
代理模式
js
var myImage = (function () {
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
},
};
})();
var proxyImage = (function () {
var img = new Image();
img.onload = function () {
myImage.setSrc(this.src);
};
return {
setSrc: function (src) {
myImage.setSrc("file:// /C:/Users/svenzeng/Desktop/loading.gif");
img.src = src;
},
};
})();
proxyImage.setSrc("http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg");
单例模式
js
var CreateDiv = function (html) {
this.html = html;
this.init();
};
CreateDiv.prototype.init = function () {
var div = document.createElement("div");
div.innerHTML = this.html;
document.body.appendChild(div);
};
var ProxySingletonCreateDiv = function () {
var instance;
return function (html) {
if (!instance) {
instance = new CreateDiv(html);
}
return instance;
};
};
var a = new ProxySingletonCreateDiv("sven1");
var b = new ProxySingletonCreateDiv("sven2");
a === b;
保证只有给弹窗,当一个弹窗打开的时候,关闭其他弹窗
发布订阅模式
二、发布-订阅模式的通用实现
js
var event = {
clientList: [],
listen: function (key, fn) {
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this, clientList[key].push(fn);
},
trigger: function () {
var key = Array.prototype.shift.call(arguments), // (1);
fns = this.clientList[key];
if (!fns || fns.length === 0) {
// 如果没有绑定对应的消息
return false;
}
for (var i = 0, fn; (fn = fns[i++]); ) {
fn.apply(this, arguments); // (2) // arguments 是 trigger 时带上的参数
}
},
remove: function (key, fn) {
var fns = this.clientList[key];
if (!fns) {
// 如果 key 对应的消息没有被人订阅,则直接返回
return false;
}
if (!fn) {
fns && (fns.length = 0);
} else {
for (var l = fns.length - 1; l >= 0; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
},
};
再定义一个 installEvent 函数,这个函数可以给所有的对象都动态安装发布—订阅功能:
js
var installEvent = function (obj) {
for (var i in event) {
obj[i] = event[i];
}
};
var salesOffices = {};
installEvent(salesOffices);
salesOffices.listen("squareMeter88", function (price) {
console.log("价格= " + price);
});
salesOffices.listen("squareMeter100", function (price) {
console.log("价格= " + price);
});
salesOffices.trigger("squareMeter88", 2000000); // 输出:2000000
salesOffices.trigger("squareMeter100", 3000000); // 输出:3000000
js
class myEvent {
constructor() {
this.target = [];
}
listen(type, fn) {
this.target[type] = this.target[type] || [];
this.target[type].push(fn);
}
trigger(type, ...args) {
const fns = this.target[type];
fns.map((i) => i(...args));
}
}
const child = new myEvent();
child.listen("type1", function (arg) {
console.log("type1", arg, "1");
});
child.listen("type2", function () {
console.log("type2", 2);
});
child.trigger("type1", 2000);
child.trigger("type2", 2000);
- 观察者模式
js
class Subject {
// 被观察者的类 被观察者 需要将观察者收集起来
constructor(name) {
this.name = name;
this.state = "非常开心";
this.observers = [];
}
attach(o) {
// 进行收集
this.observers.push(o); // on
}
setState(newState) {
this.state = newState;
this.observers.forEach((o) => o.update(this.name, newState)); // emit
}
}
class Observer {
// 观察者
constructor(name) {
this.name = name;
}
update(s, state) {
console.log(this.name + ":" + s + "当前" + state);
}
}
let s = new Subject("小宝宝");
let o1 = new Observer("爸爸");
let o2 = new Observer("妈妈");
s.attach(o1);
s.attach(o2);
s.setState("不开心了");
s.setState("开心了");
发布订阅和观察者区别
实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新
观察者 由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,这种处理方式比较直接粗暴,但是会造成代码的冗余。 发布者 中统一由调度中心进行处理,订阅者和发布者互不干扰,消除了发布者和订阅者之间的依赖。 这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息, 但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。