Dynamically add alternate processing to objects. 动态地为一个对象添加一些额外的职责,相比生成子类的形式更加灵活。
- 与 Mixin 类似,它们可以被认为是另一个可行的对象子类化的替代方案。装饰本身对于原类的基本功能来说不是必要的,所以它能够被动态添加至系统现有类的能力。
- 装饰者,可以修改现有的系统,在系统中为对象添加额外的功能之时,不需要大量修改它们的底层代码。这种模式一般会在需要大量不同类型的对象功能的时候使用。因为创建一个几百种不同类型对象的构造函数是一件可怕的事情。
- Instance decorator / Class decorator
动机:希望为对象而不是整个类添加一些功能。
适用性:
- 不影响其他类的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能够采用生成子类的方法进行扩充的时候。
代码结构:
标准的 Java 式 Decorator
interface Vehicle {run();}class Bus extends Vehicle {public run() {};}class Car extends Vehicle {public run() {};}class EngineDecorator implements Vehicle {private vehicle: Vehicle;constructor(vehicle: Vehicle, engineType: string) {this.vehicle = vehicle;this.setEngine(engineType);}setEngine(engineType: string) {this.vehicle.engineType = engineType;}getEngineSpeed() {}run() {this.engineSpeed = this.getEngineSpeed();this.vehicle.run();}}const myBus = new EngineDecorator(new Bus(), '6g');const myCar = new EngineDecorator(new Car(), '4g');
function addPrototypeChain(obj) {obj.prototype.getPrototypeChain = () => {};obj.prototype.setPrototypeChain = () => {};return obj;}function addDelayExecution(obj) {obj.delayExecution = () => {};}// ES6 Method Decorator// ES6 Class Decorator@lazyLoad('image')class Calendar extends Component {@deprecated('warning');doStuff() {// do stuff}}
实现思路:
- 满足和装饰的接口的「一致性」。因而
ConcreteDecorator需要一个父类来保证这种接口的一致性。 - 改变对象的「外壳」而非「内核」,内核交给
Strategy模式来处理。
举例:
- Java I / O 中,使用
InputStream作为实例,而FileInputStream作为一个Decorator为InputStream装饰(扩展)功能,使之具有额外处理文件流的能力。
效果:
- 比静态继承更加灵活。
- 避免在层次结构高层的类有太多的职责。
- Decorator 是透明包装。
- 有许多小对象。
类比:
- 和 Adapter 不同的是,它强调「扩展」能力,而非「适配」接口。
