装饰器模式类比生活中房屋装修的场景,可以在毛坯房的基础上加以各种装饰,使得房屋的居住属性增强。装饰器模式能够在运行期间,动态地为原始对象增加一些额外的功能,使其功能更为丰富。
1. 概述
装饰模式 可以动态的为某些对象增加一些额外的职责,在某些程度上,装饰器模式类似于继承,但是比继承更加灵活,可以在不改变一个对象本身功能的基础上额外增加新行为。装饰模式是一种对象结构性的模式。
在定义中,我们提到了继承,通过继承的方式,子类可以在父类的功能上做增加,但这是在编译期间,需要修改子类来完成的。装饰模式可以在运行期间动态的包装
原始对象,实现“装饰”的效果。
装饰模式的实现需要以下4个角色。
- 组件接口:组件接口是所有被装饰的类和装饰器抽象类共同要实现的接口标准,接口中会定义装饰的行为方法。
- 组件实现:这里是指被装饰的组件,只需实现组件接口,并且在接口行为方法中实现未被装饰的原始特性就可以。
- 装饰器:是装饰器的高层抽象类,同样实现了组件接口,同时会声明一个组件接口类型的被装饰对象,一般是抽象类。
- 装饰器实现:是
装饰器
抽象类的子类,可以有多种实现,在被装饰对象的基础上添加新的特性,真正实现功能增强的装饰器组件。
2. 代码实现
在下面的代码案例中,我们假设装修公司提供给客户两种装修方案,分别是中式装修和欧式装修,对于装饰器模式需要的4个角色,我们实现如下:
- 组件接口
// 组件接口
public interface Component {// 表示装饰的行为接口方法void fitment();
}
- 组件实现
// 毛坯房屋 - 被装饰的对象
public class RoughHouse implements Component {// 组件接口的实现方法@Overridepublic void fitment() {System.out.print("【原始的毛坯房屋】");}
}
- 装饰器
// 抽象的装饰器
public abstract class AbstractDecorator implements Component {// 声明的被装饰的对象属性protected Component component;// 构造方法中注入被装饰对象的属性public AbstractDecorator(Component component) {this.component = component;}// 装修的方法@Overridepublic void fitment() {component.fitment();}
}
- 装饰器实现
// 具体的装饰实现类 - 中式装修风格
public class ChineseStyle extends AbstractDecorator {// 构造方法的注入public ChineseStyle(Component component) {super(component);}// 功能增强的方法@Overridepublic void fitment() {System.out.print("【中式装修的吊顶");super.fitment();System.out.print("】");}
}// 具体的装饰实现类 - 欧式装修风格
public class EuropeanStyle extends AbstractDecorator {// 构造器 - 装饰对象的注入public EuropeanStyle(Component component) {super(component);}// 具体的装修风格@Overridepublic void fitment() {System.out.print("【欧式装修的家电家具");super.fitment();System.out.print("】");}
}
- 客户端
// 客户端
public class Client {public static void main(String[] args) {// 只是中式装修Component chineseStyle = new ChineseStyle(new RoughHouse());chineseStyle.fitment();System.out.println("");// 只是欧式装修Component europeanStyle = new EuropeanStyle(new RoughHouse());europeanStyle.fitment();System.out.println("");// 中式装修+欧式装修Component component = new EuropeanStyle(new ChineseStyle(new RoughHouse()));component.fitment();System.out.println("");}
}
3. UML类图
根据上述房屋装修的代码示例,我们来画一下UML类图,如下所示:
4. 使用场景
装饰器模式在某些场景下,如果只有一个具体的被装饰对象,那么抽象的装饰类可以直接作为该具体构件类的子类。
在Java类库中,最典型的装饰器模式使用就是Java IO中的输入流和输出流的设计,总体来说,装饰器模式的使用场景还是比较多的。
5. 总结
最后,我们来总结一下装饰模式的优点:
- 相对于继承,装饰器模式更灵活,也不会导致类的数量急剧增加;
- 通过装饰实现类的自由组合,可以扩展对象的不同的能力,从而实现不同的行为;
- 不同的被装饰类和装饰器实现类,都可以在不改变原有类结构的基础上,直接增加新的类型,符合开闭原则。