装饰器模式(在不改变现有对象结构的情况下,动态扩展该对象的功能)
- 优点:
1、装饰类和被装饰类可以独立发展,不会相互耦合,
2、装饰器是继承的有力补充,比继承更加灵活。
3、装饰模式可以动态扩展一个实现类的功能。 - 缺点:
1、过度使用会增加许多子类,使程序比较复杂。 - 装饰器模式主要包含以下角色
抽象类:定义实现类的接口。
具体实现类:实现抽象类的业务方法。
抽象装饰器:继承抽象类,聚合了具体实现类对象,可以通过其子类扩展具体实现类的功能。
具体装饰器:实现抽象装饰的方法,并给具体具体实现类对象添加附加的责任。 - 应用场景
1、当需要给一个现有类添加附加职责,而不能采用生成子类的方式进行扩充时。例如:该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
2、当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
3、当对象的功能要求可以动态添加,也可以再动态地撤销时。 - 例子:网店销售手机,为了提高销量,现在推出了礼品赠送的套餐一 (耳机+充电宝)和套餐二(耳机+智能手表),类图如下
抽象构件角色:
/**
* 手机
*/
public interface Phone {
void show();
}
具体构件角色:
/**
* 智能手机
*/
public class SmartPhone implements Phone {
@Override
public void show() {
System.out.println("智能手机");
}
}
抽象装饰器:
/**
* 礼品
*/
public abstract class Gift implements Phone {
private Phone phone;
public Gift(Phone phone) {
this.phone = phone;
}
@Override
public void show() {
phone.show();
}
}
具体装饰器:
/**
* 礼品一
*/
public class GiftFirst extends Gift {
public GiftFirst(Phone phone) {
super(phone);
}
@Override
public void show() {
super.show();
System.out.println("赠送耳机+充电宝");
}
}
/**
* 礼品二
*/
public class GiftSecond extends Gift {
public GiftSecond(Phone phone) {
super(phone);
}
@Override
public void show() {
super.show();
System.out.println("赠送耳机+智能手表");
}
}
测试:
public class Test {
public static void main(String[] args) {
System.out.println("原始套餐:");
Phone phone = new SmartPhone();
phone.show();
System.out.println("套餐一:");
Phone phone1 = new GiftFirst(new SmartPhone());
phone1.show();
System.out.println("套餐二:");
Phone phone2 = new GiftSecond(new SmartPhone());
phone2.show();
}
}
// 运行结果
原始套餐:
智能手机
套餐一:
智能手机
赠送耳机+充电宝
套餐二:
智能手机
赠送耳机+智能手表
- 注意
1、 如果只有一个具体实现类而没有抽象类时,可以让抽象装饰继承具体实现,类图如下
2、如果只有一个具体装饰时,可以将抽象装饰和具体装饰合并,类图如下
- 上面这个装饰器模式的类图和代理模式的类图一摸一样,对装饰器模式来说,装饰者和被装饰者都实现同一个接口。对代理模式来说,代理类和被代理类都实现同一个接口。他们之间的边界确实比较模糊,两者都是对类的方法进行扩展,具体区别如下:
装饰器模式: 强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。增强后你还是你,只不过能力更强了而已;
代理模式: 强调要让别人帮你去做一些本身与你业务没有太多关系的职责。代理模式是为了实现对象的控制,因为被代理的对象往往难以直接获得或者是其内部不想暴露出来。