为了更好的减少底层库变动对业务代码的影响,所以对于调用及操作场景的部分做了代码重构。 经历了两个多月的代码重构(实际也是新开一个项目),维护一个基础应用平台。
在重构的过程当中,使用了一些设计模式的理念,这里记录并回顾一下这些常用的设计模式
项目中的变化
Before
由于之前涉及到的巨多的关于三维场景的全局变量,目的在于方便各个操作方法中频繁的赋值及取值,但是造成了难以维护和混乱(无法跟踪何时赋值、更新、销毁等)
Now
重构的时候使用封装了一个单例 为这些变量相关的操作提供了对应的函数,并且提供了这些变量的访问接口
单例模式的特点
- 由于模块化的导出,我们避免了构造函数
MethodsLibrary
的二次实例化- 通过模块默认导出值提供了全局可访问的访问点
单例模式的概念
什么是单例模式?如何能保证全局仅有一个实例呢?
-
一个类只有一个实例,并提供一个访问它的全局访问点
-
保证构造方法只能被
new
一次。通常就是将构造方法私有化
并且需要判断是否已经创建过实例
class Single {
constructor() {
this.instance = null
}
static getInstance() {
if (!this.instance) {
this.instance = new Name()
}
return this.instance
}
}
// 或者是闭包的形式
const Single = function () {}
Single.getInstance = (function () {
let instance = null
return function () {
if (!instance) {
instance = new Single()
}
return instance
}
})()
// result
const one = Single.getInstance()
const two = Single.getInstance()
console.log(one === two) // true
JS 中的单例模式
全局变量 - 最简单的单例模式
当然这只是一个完成定义上的单例,对于 JavaScript
而言,实际上一个全局声明的变量也可以当做单例来使用; 这个在之前的项目中频繁出现,也就是定义一个全局变量。
使用 模块化 或者 闭包 之后,我们避免了变量可能因为重复声明导致的命名空间的污染
// 闭包:将一些变量封装在函数内部,可以自定义接口与外界通讯
const user = (function () {
let _name = '',
_age = ''
return {
getUser() {
return {
name: _name,
age: _age,
}
},
setUser(args = { name: '', age: '' }) {
_name = args.name
_age = args.age
},
}
})()
/*-------------------*/
// ES6 - module
// tool.js
export const handleTools = () => {}
export const toolConfig = () => {}
// main.js
import { handleTools, toolConfig } from '@/util/tool'
惰性单例
当然了,重构项目中最主要的两个单例就是
MethodsLibrary
和Vuex 提供的 Store 单例
,都是项目运行就立刻创建,但是这里不影响我们说下惰性单例的好处(默认不创建,避免浪费一些资源)
<body>
<button class="open"></button>
<button class="close"></button>
</body>
<script>
const Modal = (function () {
let modal = null
return function () {
if (!modal) {
modal = document.createElement('div')
// add some attribute...
document.body.appendChild(modal)
}
return modal
}
})()
document.querySelector('.open').addEventListener('click', () => {
const modal = new Modal() // 1.不点击就不会触发实例的创建,不需要创建多余的内容
modal.style.display = 'block'
})
document.querySelector('.close').addEventListener('click', () => {
const modal = new Modal() // 2. 获取到的依旧是那个已经被创建的实例
modal.style.display = 'none'
})
</script>