装饰模式就是使用被装饰类的一个子类实例,在客户端将这个子类的实例委托给装饰类,装饰模式是继承关系的一个替代方案。装饰模式在java io、junit中有很好的应用。
我们来看一个彩铃的例子:某手机在设计时只有打电话的功能:
Phone.java:
package com.dxy.design.pattern.decorator;
public class Phone {
public void call() {
//打电话。。。
}
}
有的用户想在打电话前增加一个彩铃提醒的功能,而有的用户又不想,所以我们可以采用继承的方式来实现:
package com.dxy.design.pattern.decorator;
public class ColorPhone extends Phone {
@Override
public void call() {
//此处播放彩铃...
super.call();//打电话
}
}
而有的用户希望在打完电话后播放一段广告,我们接着用继承来实现:
package com.dxy.design.pattern.decorator;
public class AdPhone extends Phone {
@Override
public void call() {
super.call();//打电话
//此处播放广告。。。
}
}
这时坑爹的用户们有的想即播放彩铃又播放广告,有的又想增加许多新功能,如果继续用继承会导致子类越来越多,继承关系也越复杂,当使用继承给类增加功能比较麻烦时,我们就应该考虑使用装饰模式了:
定义一个手机接口和实现:
package com.dxy.design.pattern.decorator;
public interface Phone {
public void call() ;
}
package com.dxy.design.pattern.decorator;
public class PhoneImpl implements Phone {
@Override
public void call() {
System.out.println("通话中。。。");
}
}
所谓的装饰,也就是把原有的包装一下,使其功能更多,所以这里需要一个装饰类:
手机通话装饰类:
package com.dxy.design.pattern.decorator;
public class PhoneDecorator implements Phone {
private Phone phone;
public PhoneDecorator(Phone phone) {
this.phone = phone;
}
@Override
public void call() {
this.phone.call();
}
}
如果要增加彩铃功能,就增加一个彩铃装饰类:
package com.dxy.design.pattern.decorator;
public class ColorPhoneDecorator extends PhoneDecorator {
public ColorPhoneDecorator(Phone phone) {
super(phone);
}
public void call() {
System.out.println("播放彩铃");
super.call();
}
}
如果要增加广告功能就增加一个广告装饰类:
package com.dxy.design.pattern.decorator;
public class AdPhoneDecorator extends PhoneDecorator {
public AdPhoneDecorator(Phone phone) {
super(phone);
}
public void call() {
super.call();
System.out.println("播放广告");
}
}
如果增加了彩铃功能,我们客户端可以这样调用:
package com.dxy.design.pattern.decorator;
public class Client {
public static void main(String[] args) {
Phone phone = new PhoneImpl();
PhoneDecorator pd = new ColorPhoneDecorator(phone);
pd.call();
}
}
如果增加广告,我们就可以这样调用:
package com.dxy.design.pattern.decorator;
public class Client {
public static void main(String[] args) {
Phone phone = new PhoneImpl();
PhoneDecorator pd = new AdPhoneDecorator(phone);
pd.call();
}
}
现在你也许还看不出来有什么区别,如果现在要即播放彩铃又播放广告,如果用继承的话还得增加一个新的子类,现在,我们可以这样调用:
package com.dxy.design.pattern.decorator;
public class Client {
public static void main(String[] args) {
Phone phone = new PhoneImpl();
PhoneDecorator pd = new AdPhoneDecorator(new ColorPhoneDecorator(phone));
pd.call();
}
}
怎么样,是不是很方便,这比使用继承关系更灵活的扩展了对象的功能,我们可以动态的添加对象的功能,并且对这些功能进行任意的组合进而实现更多的功能,避免了更多的继承关系的实现。