几种常用的设计模式(JS精简版)
单例模式(Singleton)
该模式应该算是最常用的一种设计模式,它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一的变量进行访问。它可以减少页面中全局变量的个数,让代码逻辑更加清晰。
-
应用
网页的弹窗,全局loading等 -
命名空间
var myNamespace = {
p1:123,
p2:'test',
add(){},
remove(){}
}
- 惰性加载
即通过一个静态方法来检查对象是否已经被实例化,若没有,则创建实例并返回,否则直接返回现有实例。
class Person {
constructor(){
this.instance = null;
}
static getInstance() {
if(!this.instance) {
this.instance = new Person();
}
return this.instance;
}
}
发布/订阅模式(Publish/Subscribe)
简单来说,就是事件监听,类似
document.body.addEventListener('click',fn)
- 简单实现
var event = {
listener: {},
on(key, fn) {
if (!this.listener[key]) {
this.listener[key] = [];
}
this.listener[key].push(fn);
},
emit(key, ...others) {
var fnPool = this.listener[key];
if (!fnPool || fnPool.length === 0) {
return false;
}
for (var i = 0, fn; fn = fnPool[i++];) {
fn.apply(this, others);
}
},
remove(key, removeFn) {
var fnPool = this.listener[key];
if (!fnPool || fnPool.length === 0) {
return false;
}
if (!removeFn) {
fnPool && (fnPool.length = 0);
} else {
for (var i = 0, fn; fn = fnPool[i]; i++) {
if (fn === removeFn) {
fnPool.splice(i, 1);
}
}
}
}
};
event.on('test', function (a, b) {
console.log(a + b)
})
setTimeout(() => {
event.emit('test', 1, 8)
}, 5000)
- jquery实现
jQuery.Callbacks( flags )
迭代器模式(Iterator)
该模式就是提供一个方法按照顺序存取一个对象中的各个元素,且迭代过程完全与业务逻辑分离。
1 内部迭代
类似forEach,$.map等等
2 外部迭代
类似es6中提供的Iterator接口
3 应用(登录验证)
function isNumber(){}
function isBoundMaxLength(){}
function isEmpty(){}
function iteratorValidator(...args){
return args.every(fn=>fn !== false)
}
var shouldLogin = iteratorValidator(isNumber(),isBoundMaxLength(),isEmpty())
实际上述实现同样可以用策略模式
策略模式(Strategy)
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。简言之,将完成一个任务中的各个方法(策略)独立出来,根据不同条件选择不同方法。
- 实现
let config = new Map([
['first_name', 'isNonEmpty'],
['age', 'isNumber'],
['username', 'isAlphaNum']
]);
class Checker {
constructor(check, instructions) {
[this.check, this.instructions] = [check, instructions];
}
}
class Validator {
constructor(config) {
[this.config, this.messages] = [config, []];
}
validate(data) {
for (let [k, v] of data.entries()) {
let type = this.config.get(k);
let checker = Validator[type];
if (!type) continue;
if (!checker) throw new Error(`No handler to validate type ${type}`);
let result = checker.check(v);
if (!result) this.messages.push(checker.instructions + ` **${v}**`);
}
}
hasError() {
return this.messages.length !== 0;
}
}
Validator.isNumber = new Checker((val) => !isNaN(val), 'the value can only be a valid number');
Validator.isNonEmpty = new Checker((val) => val !== "", 'the value can not be empty');
Validator.isAlphaNum = new Checker((val) => !/^a-z0-9/i.test(val), 'the value can not have special symbols');
let validator = new Validator(config);
let data = new Map([
['first_name', 'Super'],
['last_name', 'Man'],
['age', 'unknown'],
['username', 'o_O']
]);
validator.validate(data);
console.log(validator.messages.join('\n')); //the value can only be a valid number **unknown**
适配器模式
定义:将一个类(对象)的接口(方法或属性)转化成使用者希望的另外一个接口(方法或属性),使得原接口不兼容的类(对象)可以正常使用,即相当于增加一道兼容层。
class Test {
fn(){}
}
class TestA {
fnA(){
}
}
class Aadaptee extends TestA{
constructor(){
super()
}
fn(){
return this.fnA()
}
}
// const test = new Test()
// test.fn()
const test = new Aadaptee()
test.fn()