一, 参考文献: <<Javascipt 设计模式与开发实践>> -- 曾探
二, 设计模式的目的
- 设计模式是为了更好的代码重用性, 可读性,可靠性, 可维护性
- 学会理解了设计模式, 就会发现生活中无处不在
三, 设计模式分类
- 创建型: 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型: 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型: 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
以下我们将学习常见的设计模式:
四, 常见设计模式
1. 单例模式
- 定义: 保证一个类仅有一个实例, 并提供一个访问他的全局访问点
- 比如有些对象我们只需要一个, 比如线程池, 全局缓存, 登录, 购物车等, 这种我们适合使用单例模式
class SingleObj {
login() {}
}
SingleObj.getInstance = (function() {
let instance;
return function() {
if (!instance) {
// 如果实例没有被创建, 则创建新的实例
instance = new SingleObj();
}
return instance;
};
})();
let a = SingleObj.getInstance();
let b = SingleObj.getInstance();
// console.log("a", a == b);
- 应用场景:JQuery中的$、Vuex中的Store、Redux中的Store等
2. 策略模式
- 定义: 定义一系列的算法, 并把他们一个个封装起来, 并且使他们可以相互替换
let strategy = {
A: function(price) {
return price * 2;
},
B: function(price) {
return price * 2;
},
C: function(price) {
return price * 2;
}
};
function calc(price, type) {
return strategy[type](price);
}
calc(100, "A");
- 应用场景: 表单验证等
3. 代理模式
- 定义: 为一个对象提供一个代用品或占位符, 以便控制对他的访问
// 案例: jack 通过代理对象送花给rose
class Flower {}
class Jack {
constructor(target) {
this.target = target;
}
sendFlower(target) {
// jack送花 rose收到花
const flower = new Flower(); // 创建花
this.target.receiveFlower(flower); // 目标对象收到花
}
}
// 目标对象
class Rose {
receiveFlower(flower) {
console.log("收到花", flower);
}
}
class Proxy {
constructor() {
this.target = new Rose(); // 目标对象为rose
}
sendFlower(flower) {
// 代理对象送花
this.receiveFlower(flower);
}
// 目标对象收到花
receiveFlower(flower) {
this.target.receiveFlower(flower);
}
}
let proxyPerson = new Proxy(); // 代理对象
let jack = new Jack(proxyPerson); // 杰克
jack.sendFlower(proxyPerson); // 杰克送花
- 应用场景: ES6 proxy, Vuex中对于getters访问、图片预加载等
4. 迭代器模式
- 定义: 按一个方法顺序访问一个聚合对象中的每一个元素, 而又无需暴露该对象的内部显示
内部迭代器
- 内部定义好迭代规则, 外部只需要调用一次
const each = (args, fn) => {
for (let i = 0; i < args.length; i++) {
const value = fn(args[i], i, args);
if (!value) break; // 跳出循环
}
};
each([1, 2, 3], function(item, index) {
console.log(item, index);
});
外部迭代器
- 必须显示的请求迭代下一个元素。
class Iterator {
constructor(list) {
this.list = list;
this.index = 0;
}
next() {
if (this.hasNext()) {
return this.list[this.index++];
}
return null;
}
hasNext() {
if (this.list.length === this.index) {
return false;
}
return true;
}
}
let ite = new Iterator([1, 2, 3, 4]);
ite.next();
- 应用场景: JS Iterator、JS Generator
5. 工厂模式
- 定义: 常见的实例化对象模式
// 具体的对象
class Product {
constructor(name) {
this.name = name;
}
}
// 工厂类
class Creator {
create(name) {
return new Product(name);
}
}
let creators = new Creator();
creators.create("jojo");
- 应用场景:JQuery中的$、Vue.component异步组件、React.createElement等
6. 发布订阅者模式
- [欢迎查看本人的另外一篇文章- 发布订阅者模式解析] (juejin.cn/post/694117…)
7. 装饰者模式
- 定义: 在不改变对象本身的基础上, 在程序运行期间动态的添加方法
- 简单版
class Plane {
fire() {
console.log("开火");
}
}
class Mixin {
constructor(obj) {
this.obj = obj;
}
attack() {
this.obj.fire();
console.log("开炮");
}
}
let plane = new Plane();
let mixin = new Mixin(plane);
mixin.attack();
- 利用AOP给函数动态添加功能
Function.prototype.before = function(fn) {
let self = this; // 保存原函数引用
return function() {
fn.apply(this, arguments); // 新函数执行
return self.apply(this, arguments); // 原函数执行
};
};
Function.prototype.after = function(fn) {
let self = this;
return function() {
let ret = self.apply(this, arguments);
fn.apply(this, arguments);
return ret;
};
};
function f1() {
console.log(1);
}
let f = f1
.before(function() {
console.log(2);
})
.after(function() {
console.log(3);
});
f();
- 应用场景:ES7装饰器、Vuex中1.0版本混入Vue时,重写init方法、Vue中数组变异方法实现等
8.适配器模式
- 定义: 用来解决两个接口不兼容的问题, 由一个对象包裹不兼容的对象, 比如参数转换, 允许直接访问
class Adapter {
specify() {
return "德国标准插头";
}
}
class Target {
constructor(target) {
this.target = new Adapter();
}
requset() {
let tips = this.target.specify();
console.log(`${tips} - 转换器 - 中国标准插头`);
}
}
let target1 = new Target();
target1.requset();
9. 中介者模式
- 定义: 通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,
- 当其中的一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。
var mediator = (function() {
var colorSelect = document.getElementById("colorSelect");
var memorySelect = document.getElementById("memorySelect");
var numSelect = document.getElementById("numSelect");
return {
changed: function(obj) {
switch (obj) {
case colorSelect:
//TODO
break;
case memorySelect:
//TODO
break;
case numSelect:
//TODO
break;
}
}
};
})();
colorSelect.onchange = function() {
mediator.changed(this);
};
memorySelect.onchange = function() {
mediator.changed(this);
};
numSelect.onchange = function() {
mediator.changed(this);
};
10. 外观模式
- 为一组复杂的子系统接口提供一个更高级的统一接口, 通过这个接口更容易访问子系统接口, 不符合开放封闭原则
class A {
eat() {}
}
class B {
eat() {}
}
class C {
eat() {
const a = new A();
const b = new B();
a.eat();
b.eat();
}
}
// 跨浏览器事件监听
function addEvent(el, type, fn) {
if (window.addEventListener) {
el.addEventListener(type, fn, false);
} else if (window.attachEvent) {
el.attachEvent('on' +type, fn);
} else {
el["on" + type] = fn;
}
}
- 应用场景:JS事件不同浏览器兼容处理、同一方法可以传入不同参数兼容处理等
今天真是让人头凸且充实的一天啊~~~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!