装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
装饰器模式(Decorator Pattern)的核心作用就是动态地给一个对象添加一些额外的职责功能。适用于透明且动态扩展类功能时。这点注意跟适配器模式的区别:
- 适配器模式主要是为了接口的转换,而装饰者模式关注的是通过组合来动态的为被装饰者注入新的功能或行为(即所谓的责任)。
- 适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增强新的行为和责任;而外观将一群对象包装起来以简化其接口
这里我们可能会有疑问:为什么不使用继承的方式进行功能的扩展呢?首先装饰器模式是基于已存在类的功能进行扩展,如果使用继承的方式进行实现,需求后期都可能进行变动,这样增加很多需求,会导致子类出现太多,所以就增加功能来说,装饰器模式相比生成子类更为灵活。所以为确保后期动态增加现有类的职责,将具体功能职责划分,同时继承装饰者模式。
装饰者的UML图
装饰模式的组成对象:
- 抽象组件化对象(Component):规范实例接口,约束具体行为
- 具体组件(ConcreteComponent):一个具体的接口实现类
- 装饰角色(Decorator):持有一个Component对应的引用,用来扩展类的功能;
- 具体的装饰角色(ConcreteDecorator):根据需求进行功能的扩展;
实例代码
讲解装饰模式使用最多的例子莫过于人穿衣服的例子,人穿衣戴帽就是装饰的作用。
定义抽象类,人的角色
/**
* 定义一个人的抽象类
* @author Iflytek_dsw
*
*/
abstract class People {
private String name;
public People(String name){
this.name = name;
}
public abstract void dressed();
}
定义个具体的实例类实现接口,工人类
/**
* 抽象类的角色
* @author Iflytek_dsw
*
*/
class Worker extends People{
public Worker(String name) {
super(name);
}
@Override
public void dressed() {
System.out.println("穿工人装");
}
}
定义装饰者角色
class PeopleDecorator extends People{
private People people;
public PeopleDecorator(People people, String name) {
super(name);
this.people = people;
}
@Override
public void dressed() {
people.dressed();
}
}
定义装饰的一个具体类
class HatDecorator extends PeopleDecorator{
public HatDecorator(People people, String name) {
super(people, name);
}
@Override
public void dressed() {
super.dressed();
wearHat();
}
private void wearHat(){
System.out.print("戴帽子");
}
}
定义客户端
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
People people = new Worker("工人");
//给工人带个帽子
HatDecorator hatDecorator = new HatDecorator(people, "工人");
hatDecorator.dressed();
}
}
从中可以看出来,通过装饰模式可以动态给类增加新职责。
优点
- 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除 掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
- 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点
- 多层装饰比较复杂,类的数量略多