目录
什么是装饰器模式
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许动态地向一个对象添加新的行为。在不改变对象本身的情况下,通过将对象包装在一个装饰器中,来增强对象的功能。这个模式的核心是使用一个装饰器类,来包装一个被装饰的类,使得装饰器类可以动态地添加新的功能或者修改已有的功能。
装饰器模式的主要用途是为一个原始对象添加新的功能或者修改已有的功能,同时保持原始对象的接口不变,并且可以在运行时动态地添加或删除功能。
为什么要有装饰器模式
在开发过程中,我们经常需要扩展一个类或对象的功能,但是直接修改类或对象可能会导致代码复杂性和可维护性下降。装饰器模式提供了一种优雅的方式来扩展类或对象的功能,且无需修改基本的对象或类。它使代码更加模块化、易于维护和扩展。
装饰器模式应用场景
JS装饰器模式通常用于以下场景:
- 将对象的功能添加到已存在的对象中,而不影响原始对象的接口。
- 实现AOP(面向切面编程)并在多个组件之间共享代码。
- 通过运行时组合来实现功能,而不是继承。
举个栗子
下面我们来举 2 个例子,更加具象的理解什么是装饰器模式:
给汽车加个真皮座椅
class Car { constructor() { this.price = 10000; this.speed = '100 km/h'; } getPrice() { return this.price; } getSpeed() { return this.speed; } } // 汽车装饰器 class CarDecorator { constructor(car) { this.car = car; } getPrice() { return this.car.getPrice(); } getSpeed() { return this.car.getSpeed(); } } // 真皮座椅装饰器 class LeatherSeatsDecorator extends CarDecorator { constructor(car) { super(car); this.price = 1000; this.description = 'Leather seats'; } getPrice() { return this.car.getPrice() + this.price; } getDescription() { return this.car.getDescription() + ', ' + this.description; } } let car = new Car(); console.log(car.getPrice()); // 10000 // 带有真皮座椅的汽车 let carWithLeatherSeats = new LeatherSeatsDecorator(car); console.log(carWithLeatherSeats.getPrice()); // 11000 console.log(carWithLeatherSeats.getDescription()); // undefined, Leather seats
在上面的代码中,我们定义了一个 Car 类作为原始对象,并且定义了一个 CarDecorator 类作为装饰器类。然后我们定义了一个 LeatherSeatsDecorator 类,它继承自 CarDecorator 类,用来添加真皮座椅的功能。
一个简单的数据缓存
class DataService { fetchData() { console.log("Fetching data from server..."); return [1, 2, 3]; } } class DataCacheDecorator { constructor(dataService) { this.dataService = dataService; this.cache = null; } fetchData() { if (this.cache === null) { console.log("Cache not exist..."); this.cache = this.dataService.fetchData(); } else { console.log("Data retrieved from cache"); } return this.cache; } } let dataService = new DataService(); dataService = new DataCacheDecorator(dataService); console.log(dataService.fetchData()); console.log(dataService.fetchData());
上述代码将有如下输出:
Cache not exist...
Fetching data from server...
[1, 2, 3]
Data retrieved from cache
[1, 2, 3]
总结
JS装饰器模式提供了一种优雅的方式来扩展类或对象的功能,而无需修改基本的对象或类。它使代码更加模块化、易于维护和扩展。在适当的情况下,使用装饰器模式可以提高代码的可读性和可维护性。
为了更好的理解装饰器模式,本文选取了 2 个简单易理解的例子。真实场景下 JS 装饰器模式的应用要复杂的多,目前 ES6、TypeScript、React、Express、Koa、Mobx、Redux 等场景都已经广泛使用了 JS 装饰器,以后文章会针对上述场景进行具体详细介绍。