冬天已经来临,北方的小伙伴们是不是感觉天气一天比一天冷了呢?从秋天过渡到冬天,冷了就穿一件毛衣,如果穿上毛衣还觉得冷可能会添一件羽绒服,如果下雪天可能就需要穿上雨衣或者带上雨伞了。在我们生活中这些衣服以拓展的方式给了你温暖,但是它们并不是你的一部分,如果到了春天那么这些衣服可能会一一的脱掉了。
在软件开发过程中,有事想用一些现存的类或者组件,这些类或者组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态的拓展其功能。所有这些都可以用装饰模式来实现。
什么装饰模式
装饰模式:指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 —— 节选自百度百科
装饰模式有两种方式可以实现给一个类或者一个对象添加行为,第一种是使用继承,使用继承是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。第一种则是使用关联的方法,即将一个类的对象嵌入到另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为。
装饰模式优缺点
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创建更多子类的情况下,将对象的功能加以扩展。
优点
缺点
示例
装饰模式的主要角色如下:
类图如下所示:
代码示例:
// 抽象构件 abstract class Component { public abstract operate() : void; } // 具体构件 class ConcreteComponent extends Component { public operate() : void { console.log('do something'); } } // 装饰角色 abstract class Decorator extends Component { private component : Component = null; constructor(component : Component ) { super(); this.component = component; } public operate() : void { this.component.operate(); } } // 具体装饰者 class ConcreteDecoratorA extends Decorator { constructor(component : Component) { super(component); } // 定义自己的修饰方法 private methodA() : void { console.log('methodA修饰'); } // 重写父类方法 public operate() : void { this.methodA(); super.operate(); } } class ConcreteDecoratorB extends Decorator { constructor(component : Component) { super(component); } // 定义自己的修饰方法 private methodB() : void { console.log('methodB修饰'); } // 重写父类方法 public operate() : void { this.methodB(); super.operate(); } } function main() { let component : Component = new ConcreteComponent(); // 第一次装饰 component = new ConcreteDecoratorA(component); // 第二次装饰 component = new ConcreteDecoratorB(component); // 装饰后运行 component.operate(); } main();
总结
装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
继承是一种耦合度较大的静态关系,无法在程序运行时动态扩展。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统具有较好的松耦合性,因此使得系统更加容易维护。