一、设计模式介绍
什么是设计模式?
设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。设计模式更多的是指导思想和方法论,而不是现成的代码,当然每种设计模式都有每种语言中的具体实现方式。学习设计模式更多的是理解各种模式的内在思想和解决的问题,毕竟这是前人无数经验总结成的最佳实践,而代码实现则是对加深理解的辅助。
设计模式的类型
设计模式可以分为三大类:
- 结构型模式(Structural Patterns): 通过识别系统中组件间的简单关系来简化系统的设计。
- 创建型模式(Creational Patterns): 处理对象的创建,根据实际情况使用合适的方式创建对象。常规的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。
- 行为型模式(Behavioral Patterns): 用于识别对象之间常见的交互模式并加以实现,如此,增加了这些交互的灵活性。
一. 结构型模式(Structural Patterns)
- 外观模式(Facade Pattern)
外观模式是最常见的设计模式之一,它为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。简而言之外观设计模式就是把多个子系统中复杂逻辑进行抽象,从而提供一个更统一、更简洁、更易用的API。很多我们常用的框架和库基本都遵循了外观设计模式,比如JQuery就把复杂的原生DOM操作进行了抽象和封装,并消除了浏览器之间的兼容问题,从而提供了一个更高级更易用的版本。其实在平时工作中我们也会经常用到外观模式进行开发,只是我们不自知而已。
- 代理模式(Proxy Pattern)
当访问一个对象本身的代价太高(比如太占内存、初始化时间太长等)或者需要增加额外的逻辑又不修改对象本身时便可以使用代理。ES6中也增加了Proxy的功能。
二. 创建型模式(Creational Patterns)
- 工厂模式(Factory Pattern)
使用工厂模式之后,不再需要重复引入一个个构造函数,只需要引入工厂对象就可以方便的创建各类对象。
- 单例模式(Singleton Pattern)
当需要一个对象去贯穿整个系统执行某些任务时,单例模式就派上了用场。而除此之外的场景尽量避免单例模式的使用,因为单例模式会引入全局状态,而一个健康的系统应该避免引入过多的全局状态。
三. 行为型模式(Behavioral Patterns)
- 策略模式(Strategy Pattern)
策略模式简单描述就是:对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。最常见的使用策略模式的场景如登录鉴权,鉴权算法取决于用户的登录方式是手机、邮箱或者第三方的微信登录等等,而且登录方式也只有在运行时才能获取,获取到登录方式后再动态的配置鉴权策略。所有这些策略应该实现统一的接口,或者说有统一的行为模式。Node 生态里著名的鉴权库 Passport.js API的设计就应用了策略模式。
二、实践记录及使用案例
单例模式的示例
写一个数据存储对象
需求:项目中有一个全局的数据存储者,这个存储者只能有一个 ,不然会需要进行同步,增加复杂度
function store(){
this.state={}
if(store.install){
return store.install
}
store.install=this
}
store.install=null
var s1=new store()
var s2=new store()
s1.state.a=1
console.log(s1,s2) // store { state: { a: 1 } } store { state: { a: 1 } }
需求:vue-router必须 保障全局有且只有一个,否则的话会错乱
let _Vue
function install (Vue){
if(install.installed && _Vue===vue) return
install.installed=true
_Vue=vue
}
建造者模式的示例
编写一个编辑器插件
需求:有一个编辑器插件,初始化的时候需要配置大量参数,而且内部功能很多
// 最终类
function Editor(){
this.intt=new initHTML()
this.fontControll=new fontControll()
this.stateControll=new stateControll()
}
// 初始化html的类,最终渲染成dom
function initHTML(){}
// 初始化控制样式的方法
initHTML.prototype.initStyle=function(){}
// 初始化渲染成dom的方法
initHTML.prototype.renderDom=function(){}
// 改变字体颜色大小的类
function fontControll(){}
// 控制颜色的方法
fontControll.prototype.changeColor=function(){}
// 控制字体大小的方法
fontControll.prototype.changeFontsize=function(){}
// 改变状态类,为了前进后退
function stateControll(){
this.state=[] //存储状态
this.nowstate=0 //状态指针
}
//保存状态的方法
stateControll.prototype.saveState=function(){}
//回滚状态的方法
stateControll.prototype.saveBack=function(){
var state=this.state[this.nowstate-1]
this.fontControll.changeColor(state.color)
this.fontControll.changeFontsize(state.color)
}
//前进状态的方法
stateControll.prototype.saveGo=function(){}
window.Editor=Editor
建造者模式是把它的模块抽离出独立的类,然后在组合起来
vue初始化
需求:vue内部众多模块,而且过程复杂,vue类也可以看做是一个建造者模式
function Vue(options){
// 只允许用户用new操作符,如果直接调用就抛出警告
if(!(this instanceof Vue)){
console.warn('Vue is a constructor and should be called with the `new` keyword')
}
// 初始化配置项
this._init(options)
}
initMixin(Vue) // 初始化系统混入到Vue中去
stateMixin(Vue) // 状态系统混入到Vue中去
eventsMixin(Vue) // 事件系统的混入
lifecycleMixin(Vue) // 生命周期混入
renderMixin(Vue) // 渲染混入