设计模式概览
设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。设计模式更多的是指导思想和方法论,而不是现成的代码,当然每种设计模式都有每种语言中的具体实现方式。学习设计模式更多的是理解各种模式的内在思想和解决的问题,毕竟这是前人无数经验总结成的最佳实践,而代码实现则是对加深理解的辅助。
设计模式可以分为三大类:
结构型模式(Structural Patterns): 通过识别系统中组件间的简单关系来简化系统的设计。
创建型模式(Creational Patterns): 处理对象的创建,根据实际情况使用合适的方式创建对象。常规的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。
行为型模式(Behavioral Patterns):用于识别对象之间常见的交互模式并加以实现,如此,增加了这些交互的灵活性。
上述中一共有23种设计模式,但我们作为前端开发人员,需要了解的大概有以下10种。
前端需要了解的设计模式(10种)
创建型模式
故名思意,这些模式都是用来创建实例对象的。
1. 工厂模式
我们从简单的开始。 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
上图为例,我们构造一个简单的汽车工厂来生产汽车:
// 汽车构造函数 function SuzukiCar(color) { this.color = color; this.brand = 'Suzuki'; } // 汽车构造函数 function HondaCar(color) { this.color = color; this.brand = 'Honda'; } // 汽车构造函数 function BMWCar(color) { this.color = color; this.brand = 'BMW'; } // 汽车品牌枚举 const BRANDS = { suzuki: 1, honda: 2, bmw: 3 } /** * 汽车工厂 */ function CarFactory() { this.create = (brand, color)=> { switch (brand) { case BRANDS.suzuki: return new SuzukiCar(color); case BRANDS.honda: return new HondaCar(color); case BRANDS.bmw: return new BMWCar(color); default: break; } } }
使用一下我们的工厂:
const carFactory = new CarFactory(); const cars = []; cars.push(carFactory.create(BRANDS.suzuki, 'brown')); cars.push(carFactory.create(BRANDS.honda, 'grey')); cars.push(carFactory.create(BRANDS.bmw, 'red')); function sayHello() { console.log(`Hello, I am a ${this.color} ${this.brand} car`); } for (const car of cars) { sayHello.call(car); }
输出结果:
1. Hello, I am a brown Suzuki car 2. Hello, I am a grey Honda car 3. Hello, I am a red BMW car
使用工厂模式之后,不再需要重复引入一个个构造函数,只需要引入工厂对象就可以方便的创建各类对象。
2. 单例模式
首先我们需要理解什么是单例?
单:指的是一个。
例:指的是创建的实例。
单例:指的是创建的总是同一个实例。也就是使用类创建的实例始终是相同的。
先看下面的一段代码:
class Person{ constructor(){} } let p1 = new Person(); let p2 = new Person(); console.log(p1===p2) //false
上面这段代码,定义了一个Person类,通过这个类创建了两个实例,我们可以看到最终这两个实例是不相等的。也就是说,通过同一个类得到的实例不是同一个(这本就是理所应当),但是如果我们想始终得到的是同一个实例,那么这就是单例模式。那么下面就该介绍如何实现单例模式了:
想要实现单例模式,我们需要注意两点:
需要使用return。使用new的时候如果没有手动设置return,那么会默认返回this。但是,我们这里要使得每次返回的实例相同,也就是需要手动控制创建的对象,因此这里需要使用return。
我们需要每次return的是同一个对象。也就是说实际上在第一次实例的时候,需要把这个实例保存起来。再下一个实例的时候,直接return这个保存的实例。因此,这里需要用到闭包了。
const Person = (function(){ let instance = null; return class{ constructor(){ if(!instance){ //第一次创建实例,那么需要把实例保存 instance = this; }else{ return instance; } } } })() let p3 = new Person(); let p4 = new Person(); console.log(p3===p4) //true
从上面的代码中,我们可以看到在闭包中,使用instance变量来保存创建的实例,每次返回的都是第一次创建的实例。这样的话就实现了无论创建多少次,创建的都是同一个实例,这就是单例模式。
3. 原型模式
通俗点讲就是创建一个共享的原型,并通过拷贝这些原型创建新的对象。
在我看来,其实原型模式就是指定新创建对象的模型,更通俗一点来说就是我想要新创建的对象的原型是我指定的对象。
最简单的原型模式的实现就是通过Object.create()。Object.create(),会使用现有的对象来提供新创建的对象的__proto__。例如下方代码:
let person = { name:'hello', age:24 } let anotherPerson = Object.create(person); console.log(anotherPerson.__proto__) //{name: "hello", age: 24} anotherPerson.name = 'world'; //可以修改属性 anotherPerson.job = 'teacher';
另外,如果我们想要自己实现原型模式,而不是使用封装好的Object.create()函数,那么可以使用原型继承来实现:
function F(){} F.prototype.g = function(){} //G类继承F类 function G(){ F.call(this); } //原型继承 function Fn(){}; Fn.prototype = F.prototype; G.prototype = new Fn(); G.prototype.constructor = G;
原型模式就是创建一个指定原型的对象。如果我们需要重复创建某个对象,那么就可以使用原型模式来实现。
结构型模式
1. 装饰器模式
装饰器模式:为对象添加新功能,不改变其原有的结构和功能。
适配器模式是原有的不能用了,要重新封装接口。装饰器模式是原有的还能用,但是需要新增一些东西来完善这个功能。
比如手机壳,手机本身的功能不受影响,手机壳就是手机的装饰器模式。
class Circle { draw() { console.log('画一个圆形'); } } class Decorator { constructor(circle) { this.circle = circle; } draw() { this.circle.draw(); this.setRedBorder(circle); } setRedBorder(circle) { console.log('设置红色边框') } } // 测试 let circle = new Circle(); let client = new Decorator(circle); client.draw();
输出结果:
1. 画一个圆形 2. 设置红色边框
如今都2021了,es7也应用广泛,我们在es7中这么写(ES7装饰器):
1、安装 yarn add babel-plugin-transform-decorators-legacy
2、新建.babelrc文件,进行下面的配置
{ "presets": ["es2015", "latest"], "plugins": ["transform-decorators-legacy"] }
3、上代码
@testDec class Demo { // ... } function testDec(target) { target.isDec = true } console.log(Demo.isDec) //输出true
打印出来了true,说明@testDec这个装饰器已经成功了,函数是个装饰器,用@testDec给Demo装饰了一遍。这个target其实就是class Demo,然后给她加一个isDec。
拆解后就是下面的内容
// 装饰器原理 @decorator class A {} // 等同于 class A {} A = decorator(A) || A;