关于JS中的设计模式与单例模式
的介绍,在上一篇博客中做了介绍,详情见:JS设计模式及单例模式
好,下面我将结合一些实例,说一下我对组合模式以及观察者模式的了解:
1、组合模式:
树形
结构;被一致对待
;根部进行调用
;批量执行
;想象我们现在手上有个万能遥控器, 当我们回家, 按一下开关, 下列事情将被执行:
// 先准备一些需要批量执行的功能
class GoHome{
init(){
console.log("到家了,开门");
}
}
class OpenComputer{
init(){
console.log("开电脑");
}
}
class OpenMusic{
init(){
console.log("开音乐");
}
}
// 组合器,用来组合功能
class Comb{
constructor(){
// 准备容器,用来防止将来组合起来的功能
this.skills = [];
}
// 用来组合的功能,接收要组合的对象
add(task){
// 向容器中填入,将来准备批量使用的对象
this.skills.push(task);
}
// 用来批量执行的功能
action(){
// 拿到容器中所有的对象,才能批量执行
this.skills.forEach( val => {
val.init();
} );
}
}
// 创建一个组合器
var c = new Comb();
// 提前将,将来要批量操作的对象,组合起来
c.add( new GoHome() );
c.add( new OpenComputer() );
c.add( new OpenMusic() );
// 等待何时的时机,执行组合器的启动功能
c.action();
// 在内部,会自动执行所有已经组合起来的对象的功能
由此,我们可以总结一下组合模式的特点
:
1.批量执行
2.启动一个方法,会遍历多个方法,同时执行,有点类似于递归的感觉
3.组合模式略微耗性能,但是执行方便
目前只是一个基础组合。
高级组合:
1.组合成树状结构,每个对象下,还会有自己的子对象
2.如果执行了父对象的某个方法,所有的子对象会跟随执行
3.组合模式一般建议使用在动态的html结构上,因为组合模式的结构和html的结构,出奇的一致
4.基本对象和组合对象被一致对待, 所以要保证基本对象(叶对象)和组合对象具有一致方法
2、观察者模式:
23种软件设计模式的一种
。行为模式之一
,它的作用
是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态,或者说执行对应对象的方法(主题数据改变,通知其他相关个体,做出相应的数据更新)。降低
程序模块之间的耦合度
,便于更加灵活
的扩展和维护。观察的角度
,发现对应的状况,处理问题。观察者(订阅者)
:会随时更新自身的信息或状态(订阅者可以随时加入或离开);被观察者(发布者)
:接收到发布者发布的信息,从而做出对应的改变或执行。一对多
的对应关系。核心思想
:观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数。// 我们向某dom文档订阅了点击事件,当点击发生时,他会执行我们传入的callback
element.addEventListener("click", callback, false)
element.addEventListener("click", callback, false)
// 模拟事件监听式处理事件的过程
// 需要一个观察者(班主任),创建一个事件容器(小本本),并准备on等方法(如何操作小本本)...
function Observer(){
this.msg = {};
}
// 向小本本中添加事件,消息
Observer.prototype.on = function(type, cb){
// 判断小本本中,有没有当前传进来的这个类型
// 如何没有,走else
if(this.msg[type]){
// 如果有,直接给第一次设置的这个数组,添加个新数据
this.msg[type].push(cb);
}else{
// 给他设置一个对应的属性,同时,属性值需要提前写成数组
this.msg[type] = [cb];
}
}
Observer.prototype.emit = function(type){
// 首先判断小本本中是不是已经记录
if(this.msg[type]){
var event = {
type:type
}
// 如果已经记录了信息,那么就去执行这个消息对应的所有的处理函数
this.msg[type].forEach(val=>{
val.call(this,event);
})
}
}
Observer.prototype.off = function(type, cb){
// 首先判断小本本中是不是已经记录
if(this.msg[type]){
// 准备保存符合传参的处理函数的索引
var i = 0;
// 遍历,判断,当前类型对应的每一个处理函数,依次作比较
var onoff = this.msg[type].some((val, idx)=>{
i = idx;
return val === cb;
})
// 判断是否获取到重复的函数
if(onoff){
// 如果有,那么就在当前的消息处理函数的队列中,删除这个函数
this.msg[type].splice(i, 1);
}
}
}
// 首先创建一个观察者对象
var ob = new Observer();
// 准备两个处理函数
function a(){
console.log("找来谈话");
console.log(this);
}
function b(){
console.log("叫来家长");
}
// 随便绑定一个消息,给了两个处理函数
ob.on("早恋",a);
ob.on("早恋",b);
// 模拟事件的执行
ob.emit("早恋");
// 删除一个处理函数
ob.off("早恋", b);
// 模拟事件的执行
ob.emit("早恋");
②
var obj = {
data: {
list: []
},
}
// defineProperty 可以观察 obj对象 的list 属性的使用
Object.defineProperty(obj, 'list', {
get() {
console.log('获取了list 属性');
console.log(this.data['list']);
return this.data['list'];
},
set(val) {
console.log('值被更改了'):
this.data['list'] = val;
}
})
// 获取了list属性,那么get 方法就会被调用
console.log(obj.list);
// 设置了list属性set 方法就会被调用
obj.list = ['a', 'b'];
注意:观察者模式中,需要执行的内容存储在消息盒子中;on方法 , 添加要执行的操作;emit , 发布执行操作;off , 删除执行的操作。
3、策略模式:
策略模式的定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。也就是:给出多个计划,当将来发生某种状态时,执行对应的计划。
目的
就是将算法的使用算法的实现分离开来。至少由两部分
组成。①
第一个部分是一组策略类(可变),策略类封装了具体的算法,并负责具体的计算过程。②
第二个部分是环境类Context(不变),Context接受客户的请求,随后将请求委托给某一个策略类。要做到这一点,说明Context中要维持对某个策略对象的引用。/*策略类*/
var test = {
"A": function (money) {
return money + 6;
},
"B": function (money) {
return money + 4;
},
"C": function (money) {
return money + 2;
}
};
/*环境类*/
var calculateBouns = function (level, money) {
return test[level](money);
};
console.log(calculateBouns('A', 6)); // 12
console.log(calculateBouns('B', 6)); // 10
console.log(calculateBouns('C', 6)); // 8
策略模式的优点:
- 策略模式是封装了一个充满各种算法的对象,这些算法可以供各种对象使用,可以供给给任何条件判断。
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句,即策略模式可以有效避免很多if条件语句。
- 策略模式符合开放——封闭原则,使代码更容易理解和扩展。
- 策略模式中的代码可以复用。