简单理解装饰模式
智能手机是使用装饰模式的一个例子。当你给通讯录的人发短信时,不用装任何软件。当你想和QQ好友聊天时,就要装一个QQ。当你又想和微信好友聊天时,就再装一个微信。所有这些软件都“扩展”了手机的基本功能,但它们并不是手机出厂时的一部分,当你不想用某个软件时,可以随时卸载掉。
装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
使用场景
- 想透明并且动态地给对象增加新的职责的时候
- 给对象增加的职责,在未来存在增加或减少功能
- 用继承扩展功能不太现实的情况下,应该考虑用组合的方式
结构
- Component:抽象构件角色,给出一个抽象接口,以规范准备接受附加责任的对象。
- ConcreteComponent:具体构件角色,定义一个将要接收附加责任的类。
- Decorator:装饰角色,持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- ConcreteDecorator:具体装饰角色,负责给构件对象“贴上”附加的责任。
实现代码
Component
Phone
public interface Phone {
void contact();
}
ConcreteComponent
PhoneImpl
public class PhoneImpl implements Phone{
@Override
public void contact() {
System.out.println("用短信联系");
}
}
Decorator
App
public class App implements Phone{
private Phone phone;
public App(Phone phone) {
this.phone = phone;
}
@Override
public void contact() {
phone.contact();
}
}
ConcreteDecorator
public class QQ extends App{
public QQ(Phone phone) {
super(phone);
}
public void talk(){
System.out.println("用QQ联系");
}
@Override
public void contact(){
super.contact();
talk();
}
}
public class Wechat extends App{
public Wechat(Phone phone) {
super(phone);
}
public void talk(){
System.out.println("用Wechat联系");
}
@Override
public void contact(){
super.contact();
talk();
}
}
Client
Client
public class Client {
public static void main(String[] args) {
System.out.println("===========什么软件都没装的手机");
// 什么软件都没装的手机
Phone phone = new PhoneImpl();
phone .contact();
System.out.println("===========装了QQ的手机");
// 装了QQ的手机
Phone phone1 = new QQ(phone);
phone1.contact();
System.out.println("===========装了微信的手机");
// 装了微信的手机
Phone phone2 = new Wechat(phone);
phone2.contact();
System.out.println("===========装了QQ和微信的手机");
// 装了QQ和微信的手机
Phone phone3 = new Wechat(new QQ(phone));
phone3.contact();
}
}
测试结果
===========什么软件都没装的手机
用短信联系
===========装了QQ的手机
用短信联系
用QQ联系
===========装了微信的手机
用短信联系
用Wechat联系
===========装了QQ和微信的手机
用短信联系
用QQ联系
用Wechat联系
装饰模式的优缺点
优点
- 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
- 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
缺点
- 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
- 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。