设计模式笔记

单例模式 定义 确保一个类仅有一个实例,并提供一个访问它的全局访问点。(多次实例化类也只创建一个实例对象)
实现

// 单例构造函数 function CreateSingleton (name) { this.name = name; this.getName(); }; // 获取实例的名字 CreateSingleton.prototype.getName = function() { console.log(this.name) }; // 单例对象 var Singleton = (function(){ var instance; return function (name) { if(!instance) { instance = new CreateSingleton(name); } return instance; } })(); // 创建实例对象1 var a = new Singleton('a'); // 创建实例对象2 var b = new Singleton('b'); console.log(a===b);

场景 模态框
策略模式 定义 一些列算法,把他们封装起来,并且可以相互替换。(就是把看似毫无联系的代码提取封装、复用,使之更容易被理解和拓展)
实现 1.定义方法(表单校验的方法)
const strategies = { // 非空 noEmpty: function(value, errMsg){ if(value =https://www.it610.com/article/==''){ return errMsg } }, // 最小长度 minLength: function(value, length, errMsg){ if(!value || value.length < length){ return errMsg } }, // 最大长度 maxLength: function(value, length, errMsg){ if(value.length > length){ return errMsg } } }

2.设置校验器
// 创建验证器 var Validator = function(strategies){ this.strategies = strategies this.cache = [] // 存储校验规则 } // 添加校验规则 Validator.prototype.add = function(dom, rules){ rules.forEach(item => { this.cache.push(() => { let value = https://www.it610.com/article/dom.value let arr = item.rule.split(':') let name = arr.shift() let params = [value, ...arr, item.errMsg] // apply保证上下文一致 return this.strategies[name].apply(dom, params) }) }) } // 校验结果 Validator.prototype.validate = function(dom, rules, errMsg){ // 遍历cache里面的校验函数 for(let i = 0, validateFun; validateFun = this.cache[i++]; ){ const message = validateFun() // 返回报错信息,终止验证并抛出异常 if(message) return message } }

3.进行校验
// 校验函数 function validate(){ // 实例验证器 const validator = new Validator(strategies) // 添加验证规则 validator.add(form.username, [ { rule: 'noEmpty', errMsg: '用户名不能为空!' }, { rule: 'minLength:3', errMsg: '用户名长度大于3!' } ]) validator.add(form.password, [ { rule: 'minLength:6', errMsg: '密码长度大于6!' }, { rule: 'maxLength:10', errMsg: '密码最大长度为10!' } ]) // 进行校验,并返回结果 return validator.validate() }

使用场景 表单校验,多层if-else,switch判断
代理模式 定义 为其他对象提供一种代理以控制对这个对象的访问(拦截,中间层,避免直接修改原对象)
缓存代理实现
const getCacheProxy = (fn, cache = new Map()) => { return new Proxy(fn, { apply(target, context, args) { const argsString = args.join(' '); if (cache.has(argsString)) { // 如果有缓存,直接返回缓存数据console.log(`输出${args}的缓存结果: ${cache.get(argsString)}`); return cache.get(argsString); } const result = fn(...args); cache.set(argsString, result); return result; } }) }

调用
const getFibProxy = getCacheProxy(getFib); getFibProxy(40);

场景 设置私有属性,网络访问需要设置拦截时,缓存等。
发布订阅 定义 一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。(一对多)
实现思路
  • 在该对象上创建一个缓存列表(调度中心Event Channel)
  • on方法用来把函数添加到缓存列表中(订阅者注册事件到调度中心)
  • emit方法取到argument里第一个当作event,根据event值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
  • off方法可以根据event值取消订阅(取消订阅)
  • once方法只监听一次,调用完毕后删除缓存函数(订阅一次)
代码实现
class EventEmitter { constructor() { // 缓存列表 this.listener = {} }// 订阅 on(eventName, fn) { // 如果对象中没有对应的 event 值,也就是说明没有订阅过,就给 event 创建个缓存列表 // 如有对象中有相应的 event 值,把 fn 添加到对应 event 的缓存列表里 if(!this.listener[eventName]){ this.listener[eventName] = []; } this.listener[eventName].push(fn); }// 取消订阅 off(eventName, fn) { let callbacks = this.listener[eventName]; // 缓存列表中没有对应的fn,返回false if(!callbacks){ return false; } if(!fn){ // 如果未传入fn,则将缓存列表中对应的fn都清空 callbacks && (callbacks.length = 0); } else { let cb; // 遍历所对应的fn,判断和那个fn相同,相同则删除 for (let i = 0, cbLen = callbacks.length; i < cbLen; i++) { cb = callbacks[i]; if (cb == fn || cb.fn == fn) { callbacks.splice(i, 1); break } } } }// 监听一次 once(eventName, fn) { // 先绑定,运行时删除对应的值 let on = () => { this.off(eventName, on); fn.apply(this, arguments); }on.fn = fn; this.on(eventName, on); }// 发布 emit(eventName, data) { const callbacks = this.listener[eventName]; if(callbacks) { callbacks.forEach((c) => { c(data); }) } } }let a = new EventEmitter(); function aa(x) { console.log(x); } a.on("kak", aa) a.on("kak", (data) => { console.log("1", data); })a.emit('kak', 'hahahah'); a.off('kak',aa); a.emit('kak', 'hahahah');

场景 【设计模式笔记】权限状态,一对多的场景。
中介者模式 定义 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。(是对象与对象之间)
实现
// 创建中介者 var Mediator = function() { var _msg = {} return { register: function(type, action) { if (!_msg[type]) _msg[type] = [] _msg[type].push(action) }, send: function(type) { if(_msg[type]) { for (var i = 0; i < _msg[type].length; i++) { _msg[type][i] && _msg[type][i]() } } } } }()Mediator.register('demo', function () { console.log('first') }) Mediator.register('demo', function () { console.log('second') }) Mediator.send('demo')

场景 商品选择不同颜色,尺码(等不同维度)时显示库存
组合模式 定义 又叫 “部分整体” 模式,将对象组合成树形结构,以表示 “部分-整体” 的层次结构。通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性。(文件访问目录,tree结构)。对外暴露统一接口,访问顶层对象时会自上而下遍历子对象。
实现
// 树对象 - 文件目录 class CFolder { constructor(name) { this.name = name; this.files = []; }add(file) { this.files.push(file); }scan() { for (let file of this.files) { file.scan(); } } }// 叶对象 - 文件 class CFile { constructor(name) { this.name = name; }add(file) { throw new Error('文件下面不能再添加文件'); }scan() { console.log(`开始扫描文件:${this.name}`); } }let mediaFolder = new CFolder('娱乐'); let movieFolder = new CFolder('电影'); let musicFolder = new CFolder('音乐'); let file1 = new CFile('钢铁侠.mp4'); let file2 = new CFile('再谈记忆.mp3'); movieFolder.add(file1); musicFolder.add(file2); mediaFolder.add(movieFolder); mediaFolder.add(musicFolder); mediaFolder.scan(); /* 输出: 开始扫描文件:钢铁侠.mp4 开始扫描文件:再谈记忆.mp3 */

场景 树形结构查找(地区级联显示
责任链模式 定义 使多个对象都有机会处理请求,从而避免了请求的发送者与多个接收者直接的耦合关系,将这些接收者连接成一条链,顺着这条链传递该请求,直到找到能处理该请求的对象。
实现
function order500 (orderType, pay, stock) { if (orderType === 1 && pay === true) { console.log('500元定金预购,得到100元优惠券') } else { return 'nextSuccessor' } }function order200 (orderType, pay, stock) { if (orderType === 2 && pay === true) { console.log('200元定金预购,得到50元优惠券') } else { return 'nextSuccessor' } }function orderNormal (orderType, pay, stock) { if (stock > 0) { console.log('普通用户购买,无优惠券') } else { console.log('手机库存不足') } }

使用AOP创建职责链
Function.prototype.after = function (fn) { const self = this return function () { const res = self.apply(this, arguments) if (res === 'nextSuccessor') { return fn.apply(this, arguments) } return res } }const order = order500.after(order200).after(orderNormal) order(1, true, 500)// 500元定金预购,得到100元优惠券 order(2, true, 500)// 200元定金预购,得到50元优惠券 order(3, true, 500)// 普通用户购买,无优惠券 order(1, false, 0)// 手机库存不足

使用场景 商品促销不同顾客优惠力度不同的购买

    推荐阅读