装饰模式
定义:装饰模式以对客户端透明的方式扩展对象的功能,是继承方案的一个替代方案,提供比继承更多的灵活性。
优点:能够提供比使用继承关系更加灵活的拓展对象的功能,它可以动态增加对象的功能并且可以随意组合这些功能。
缺点:使用装饰模式进行设计往往会产生很多看上去相似的小对象。
使用时机:当系统需要扩展一个类的功能,或者客户端需要动态的给一个对象添加功能,并且使用继承会很复杂时候。
其实对于装饰者模式大家并不陌生,相反接触的还很平凡,因为Java中的IO机制就用到了装饰者模式。比如大家最常用的语句:
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filepath)));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
就是最常见的装饰者模式了,通过BufferedReader对已有对象FileReader的功能进行加强和优化。其实它不仅可以加强FileReader,所有的字符输入流都可以通过这种方式进行包装。它是如何实现的呢?注意重点来了:其实很简单,它只不过将所有的字符输入流抽象出了一个基类或接口 即Reader,然后通过构造方法的形式将Reader传递给BufferedReader,此时BufferedReader就可以对所有的字符输入流进行拦截和优化了。
试想一下,如果采用继承机制,每个XXXReader就要衍生出一个BufferedXXXReader,再加上字符输出流和字节输入输出流,那么Java的IO体系结构该是多么的臃肿不堪啊!而装饰者模式的出现解决了这个问题,并且,装饰者的出现也再一次的证明了面向对象的设计原则:多用组合,少用继承!对扩展开放,对修改关闭!
下面再给出一个例子,
小巩需要为公司设计手机相关的业务,
public interface Phone {
void call(String name);
}
public class PhoneImpl implements Phone {
public void call(String name) {
System.out.println(name + " 正在通话中");
}
}
彩铃手机
public class ColorPhoneDecorator extends PhoneDecorator {
public ColorPhoneDecorator(Phone phone) {
super(phone);
}
public void call(String name) {
System.out.println("播放彩铃");
super.call(name);
}
}
广告手机
public class AdPhoneDecorator extends PhoneDecorator {
public AdPhoneDecorator(Phone phone) {
super(phone);
}
public void call(String name) {
super.call(name);
System.out.println("播放广告");
}
}
假如客户需要支持彩铃和广告的手机
public class Client {
public static void main(String[] argv) {
Phone phone = new PhoneImpl();
//如果需要彩铃的手机
PhoneDecorator phoneDecorator = new ColorPhoneDecorator(phone);
// phoneDecorator.call("张三");
//如果需要广告的手机
//phoneDecorator = new AdPhoneDecorator(phone);
//phoneDecorator.call("张三");
//如果需要既播放彩铃又播放广告的手机
phoneDecorator = new AdPhoneDecorator(phoneDecorator);
phoneDecorator.call("张三");
}
}