小册 JavaScript 设计模式核⼼原理与应⽤实践
- 重要: 工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)、单例模式、原型模式、构造器模式
⭐工厂模式
简单工厂模式
工厂方法模式
工厂模式其实就是将创建对象的过程单独封装。工厂模式的目的,就是为了实现无脑传参
 
// 构造函数function User(name , age, career, work) {this.name = namethis.age = agethis.career = careerthis.work = work}function Factory(name, age, career) {let workswitch(career) {case 'coder':work = ['写代码','写系分', '修Bug']breakcase 'product manager':work = ['订会议室', '写PRD', '催更']breakcase 'boss':work = ['喝茶', '看报', '见客户']case 'xxx':// 其它工种的职责分配...return new User(name, age, career, work)}
将创建对象的过程单独封装,这样的操作就是工厂模式。同时它的应用场景也非常容易识别:有构造函数的地方,我们就应该想到简单工厂;在写了大量构造函数、调用了大量的 new、自觉非常不爽的情况下,我们就应该思考是不是可以掏出工厂模式重构我们的代码了。
抽象工厂模式
抽象工厂目前来说在JS世界里也应用得并不广泛
抽象工厂模式的定义,是围绕一个超级工厂创建其他工厂。
- 抽象工厂: 用于声明最终目标产品的共性。
 - 具体工厂: 继承自抽象工厂、实现了抽象工厂里声明的那些方法。
```javascript
// 定义操作系统这类产品的抽象产品类
class OS {
  controlHardWare() {
} }throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
 
// 定义具体操作系统的具体产品类 class AndroidOS extends OS { controlHardWare() { console.log(‘我会用安卓的方式去操作硬件’) } }
class AppleOS extends OS { controlHardWare() { console.log(‘我会用🍎的方式去操作硬件’) } } …
class MobilePhoneFactory { // 提供操作系统的接口 createOS(){ throw new Error(“抽象工厂方法不允许直接调用,你需要将我重写!”); } // 提供硬件的接口 createHardWare(){ throw new Error(“抽象工厂方法不允许直接调用,你需要将我重写!”); } }
// 具体工厂继承自抽象工厂 class FakeStarFactory extends MobilePhoneFactory { createOS() { // 提供安卓系统实例 return new AndroidOS() } createHardWare() { // 提供高通硬件实例 return new QualcommHardWare() } }
// 这是我的手机 const myPhone = new FakeStarFactory() // 让它拥有操作系统 const myOS = myPhone.createOS() // 让它拥有硬件 const myHardWare = myPhone.createHardWare() // 启动操作系统(输出‘我会用安卓的方式去操作硬件’) myOS.controlHardWare() // 唤醒硬件(输出‘我会用高通的方式去运转’) myHardWare.operateByOrder()
> **抽象工厂是佐证“开放封闭原则”的良好素材**<br /><a name="C00YM"></a># ⭐单例模式**单例模式就是保证一个类仅有一个实例,并提供一个访问它的全局访问点**> 单例模式想要做到的是,**不管我们尝试去创建多少次,它都只给你返回第一次所创建的那唯一的一个实例**。> 要做到这一点,就需要构造函数**具备判断自己是否已经创建过一个实例**的能力。```javascriptclass SingleDog {show() {console.log('我是一个单例对象')}static getInstance() {// 判断是否已经new过1个实例if (!SingleDog.instance) {// 若这个唯一的实例不存在,那么先创建它SingleDog.instance = new SingleDog()}// 如果这个唯一的实例已经存在,则直接返回return SingleDog.instance}}const s1 = SingleDog.getInstance()const s2 = SingleDog.getInstance()// trues1 === s2
实现一个 Storage
实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)。
//静态方法版本:class Storage{static getInstance(){if(!Storage.instance){Storage.instance = new Storage()}return Storage.instance}getItem(key){return localStorage.getItem(key)}setItem(key,value){localStorage.setItem(key,value)}}const storage2 = Storage.getInstance()storage1.setItem('name', '李雷')// 李雷storage1.getItem('name')// 也是李雷storage2.getItem('name')// 返回truestorage1 === storage2//闭包版// 先实现一个基础的StorageBase类,把getItem和setItem方法放在它的原型链上function StorageBase(){}StorageBase.prototype.getItem = function(key){return localStorage.getItem(key)}StorageBase.prototype.setItem = function(key,value){return localStorage.setItem(key,value)}// 以闭包的形式创建一个引用自由变量的构造函数const Storage = (functon(){let instance = nullreturn function(){if(!instance){instance = new StorageBase()}return instance}})()// 这里其实不用 new Storage 的形式调用,直接 Storage() 也会有一样的效果const storage1 = new Storage()const storage2 = new Storage()storage1.setItem('name', '李雷')// 李雷storage1.getItem('name')// 也是李雷storage2.getItem('name')// 返回truestorage1 === storage2
实现一个模态框
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>单例模式弹框</title></head><style>#modal {height: 200px;width: 200px;line-height: 200px;position: fixed;left: 50%;top: 50%;transform: translate(-50%, -50%);border: 1px solid black;text-align: center;}</style><body><button id='open'>打开弹框</button><button id='close'>关闭弹框</button></body><script>// 核心逻辑,这里采用了闭包思路来实现单例模式const Modal = (function() {let modal = nullreturn function() {if(!modal) {modal = document.createElement('div')modal.innerHTML = '我是一个全局唯一的Modal'modal.id = 'modal'modal.style.display = 'none'document.body.appendChild(modal)}return modal}})()// 点击打开按钮展示模态框document.getElementById('open').addEventListener('click', function() {// 未点击则不创建modal实例,避免不必要的内存占用;//此处不用 new Modal 的形式调用也可以,和 Storage 同理const modal = new Modal()modal.style.display = 'block'})// 点击关闭按钮隐藏模态框document.getElementById('close').addEventListener('click', function() {const modal = new Modal()if(modal) {modal.style.display = 'none'}})</script></html>
原型模式
原型模式不仅是一种设计模式,它还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基。
在原型模式下,当我们想要创建一个对象时,会先找到一个对象作为原型,然后通过克隆原型的方式来创建出一个与原型一样(共享一套数据/方法)的对象。
在 JavaScript 里,
Object.create方法就是原型模式的天然实现——准确地说,只要我们还在借助Prototype来实现对象的创建和原型的继承,那么我们就是在应用原型模式。
