文章目录
为什么要使用设计模式呢?有什么优点。
是一套被反复使用,多数人知晓,经过分类 ,代码设计经验的总结
目的:为了代码的可重用性,让代码更容易被他人理解,保证代码的可用性。
代码设计原则
1. 开闭原则
「对扩展开放,对修改关闭」
2. 里氏替换原则
继承必须确保基类所拥有的性质在子类中仍然成立。即, 子类可以扩展父类的功能,但不能改变父类原有的功能。
3. 依赖倒置原则
要面向接口编程,不要面向实现编程
4. 单一职责原则
一个类或者一个模块只负责完成一个职责或者功能,不要设计大而全的类, 要设计粒度小,功能单一的类, 单一职责是为了实现代码高内聚,低耦合,提高代码的复用性,可读性,可维护性。
5. 接口隔离原则
对接口依赖的隔离
创建型设计模式
1. 单例模式
保证一个类只有一个实例,并提供一个全局访问点。
实现方法:先判断实例是否存在,不存在先创建后返回,存在则直接返回。
代码实现
let CreateDiv = function(html) {
this.html = html;
};
let Singleton = (function() {
let instance;
return function(html) {
if (!instance) {
instance = new CreateDiv(html);
}
return instance;
}
})();
let a = new Singleton('seven1');
let b = new Singleton('seven2');
console.log(a);
console.log(b);
console.log(a === b); // true
执行结果:
实际应用
- 模态框,以及弹框(任意一个网站,点击登录按钮,只会弹出有且仅有一个登录框,即使后面再点击登录按钮,也不会再弹出多一个弹框。这就是单例模式的典型应用。)
- windows的回收站,网站的计数器,购物车的场景
- Math,localStorage,sessionStorage
- Vuex Redux 的 store
2. 工厂模式
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。
代码实现
function CreatePerson(name,age,sex) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function(){
return this.name;
};
return obj;
}
var p1 = new CreatePerson("longen",'28','男');
var p2 = new CreatePerson("tugenhua",'27','女');
// 返回都是object 无法识别对象的类型 不知道他们是哪个对象的实列
console.log(typeof p1); // object
console.log(typeof p2); // object
console.log(p1 instanceof Object); // true
实际应用
日常封装公用方法,比如增加 node 中间层,对每个接口做一次转发
结构型设计模式
1. 装饰者模式
在不改变原对象的基础上,通过对其进行包装拓展(添加属性和方法)使原有对象更加满足用户的复杂需求。
代码实现
let decorate = function(input, fn){
let input = document.getElementById("input");
if(typeof input.onclick === "function"){
var oldClickFn = input.onclick;
input.onclick = function(){
oldClickFn();
fn();
}
}
else{
input.onclick = fn();
}
}
上面是一个简单的例子,讲的是为所有的input输入时做一定的操作。
2. 代理模式
由于一个对象不能直接应用另一个对象,所以需要通过代理对象其搭配中间作用
跨域就很好的反映了这一点。
3. 责任链模式
当你负责的模块,基本满足以下情况时
- 你负责的是一个完整流程,或你只负责流程中的某个环节
- 各环节可复用
- 各环节有一定的执行顺序
- 各环节可重组
4. 适配器模式
将一个类的接口转换为客户希望的另外一个接口,适配器模式可以使原本不兼容的接口在一起工作
行为型设计模式
1. 发布订阅者模式
当你负责的模块,基本满足以下情况时
- 各模块相互独立
- 存在一对多的依赖关系
- 依赖模块不稳定、依赖关系不稳定
- 各模块由不同的人员、团队开发
代码实现
2. 观察者模式
代码实现
/**
* 观察监听一个对象成员的变化
* @param {Object} obj 观察的对象
* @param {String} targetVariable 观察的对象成员
* @param {Function} callback 目标变化触发的回调
*/
function observer(obj, targetVariable, callback) {
if (!obj.data) {
obj.data = {}
}
Object.defineProperty(obj, targetVariable, {
get() {
return this.data[targetVariable]
},
set(val) {
this.data[targetVariable] = val
// 目标主动通知观察者
callback && callback(val)
},
})
if (obj.data[targetVariable]) {
callback && callback(obj.data[targetVariable])
}
}
发布订阅者和观察者区别
1、发布订阅者模式
从耦合度上来看,订阅发布模式是一个事件中心调度模式,订阅者和发布者是没有直接关联的,通过事件中心进行关联,两者是解耦的。
有三个角色:
- 发布者
- 事件中心
- 订阅者
2、观察者模式
而观察者模式中目标和观察者是直接关联的,耦合在一起(有些观念说观察者是解耦,解耦的是业务代码,不是目标和观察者本身)。
有两个角色:
- 目标
- 观察者
博客主要是借鉴《Javascript设计模式》,书里讲的非常通俗易通,用对话方式讲解结合实际开发中遇到的问题,使得本来枯燥的设计模式也变得浅显易懂。
设计模式网站