介绍
装饰者模式又称为包装模式,平时开发中,我们想要扩展一个现有对象,一般的做法是继承这个对象,然后在子类中添加功能,而装饰者模式就是继承的一种替代方案,也是一种动态扩展对象功能的方法。
定义
动态的给一个对象添加一些额外的职责。
使用场景
需要动态且透明地扩展类的功能时,
类图
角色介绍:
- Component: 抽象组件,可以是接口或抽象类,其实是被装饰的原始对象。
- ConcreteComponent:抽象组件具体的实现类,也就是我们装饰的具体对象。
- Decorator:抽象装饰者,其职责是为了装饰我们的组件对象,其内部一定要含有一个指向组件对象的引用。在大多数情况下该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类,但是,如果装饰的功能单一,只有一个的情况下我们可以直接使用该类作为具体的装饰者。
- ConcreteDecoratorA、B:装饰者的具体实现(如果装饰的功能单一,可以省略)。
简单示例
我们平常买一台新手机时,到手的就是一台裸机,没有贴膜,没有保护套,这些装饰都是我们后来加上去的,我们以此为例,把手机定义成一个抽象类:
/**
* 手机抽象类,即抽象组件角色,要被装饰的对象
*/
public abstract class Phone {
public abstract void operate();//Phone类下有一个关于手机的抽象操作
}
Phone类就是上面提到的抽象组件类,也就是要被我们装饰的原始对象,然后我们来定义一个具体的被装饰类,例如小米手机:
/**
* 小米手机,即抽象组件的具体实现类
*/
public class MIPhone extends Phone {
@Override
public void operate() {
System.out.println("一台崭新的小米手机");
}
}
MIPhone类继承于Phone类,对operate方法作了具体的实现,MIPhone就是我们要装饰的具体对象,现在需要一个装饰者来装饰MIPhone,这里定义一个PhoneDecorator:
/**
* 表示装饰手机,即装饰者角色
*/
public class PhoneDecorator extends Phone{
private Phone mPhone;//保持一个对被装饰者的引用
public PhoneDecorator(Phone phone){
this.mPhone = phone;
}
@Override
public void operate() {
operateA();
mPhone.operate();//调用Phone类中的operate方法
operateB();
}
private void operateA(){
System.out.println("装上手机套");
}
private void operateB(){
System.out.println("贴膜");
}
}
在PhoneDecorator中我们保持了一个对Phone类的引用,可以方便的调用具体被装饰对象中的具体方法,然后PhoneDecorator中添加了两个新方法,分别表示对Phone的装饰,然后重写继承自Phone的operate方法,实现装饰逻辑。可以看到这里我并没有定义想类图那样抽象的装饰者,而是直接只定义了一个具体的装饰者类,这是因为我们要添加的装饰并不是很复杂,就没有对装饰者做抽象的提取,如果你要为Phone类添加不同牌子的配件,就可以考虑像类图那样的结构,把装饰者做抽象的提取,然后定义多个具体的装饰着实现。所以开发中要灵活运用,结合实际,不要为了用设计模式而用设计模式。
接下来再看具体的调用:
/**
* 客户端
*/
public class Client {
public static void main(String[] args){
//我买了一台手机
Phone phone = new MIPhone();
//我给手机买一些配件
PhoneDecorator phoneDecorator = new PhoneDecorator(phone);
phoneDecorator.operate();
}
}
输出:
装上手机套
一台崭新的小米手机
贴膜
结语
装饰者模式是一个很简单的设计模式,但是它在日常开发中使用的也比较多,而且他和前面讲过的代理模式很相似,不要混淆,这里说一下它们之间的区别:
装饰者模式是一种透明的扩展对象功能的方法,是继承关系的一种代替方案,而代理模式则是给一个对象提供一个代理对象,并且通过代理对象控制原有对象的引用。装饰者模式侧重为装饰对象增强功能,代理模式侧重对代理对象施加控制,但没有功能增强。