定义:
装饰者模式:指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
特点:
优点:
1、装饰者和被装饰者继承或实现同一个装饰类或接口
2、装饰模式可以提供比继承更高的灵活性
3、可以通过一种动态的功能来扩展一个类的功能,在运行时选择不同的装饰器,从而实现不同的行为。
4、组合具体的装饰类,可以创建很多不同行为的组合。可以使用具体的装饰类来装饰同一个对象,获得功能更加强大的对象。
5、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点:
1、会产生很多的小对象,增加了系统的复杂
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
具体使用场景:
1、在java I/O流中的使用
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("d:/text.txt"))));
这种对File类的包装,由内层到外层扩展输入流的功能,就是一个典型的装饰者模式。inputstream是被装饰对象,然后Fileinputstream、InputStream、BufferedReader都是它的装饰器,用来扩展它的功能!
2、在struts2框架中的使用
JavaEE API 中的 ServletRequestWrapper、HttpServletRequestWrapper 对于 ServletRequest 的封装 (Struts2 中的 StrutsRequestWrapper 对 HttpServletRequestWrapper 进行了继承扩展,对 ServletRequest 进一步封装,也属于装饰者模式的应用之一)
3、Android 中使用
对于 android 开发工程师来说,最最重要的就应该是“上帝类” Context 和其子类了
所以对于 Application,Activity 和 Service 等类来说,他们只是一个个装饰者,都是用来装饰 ContextImpl 这个被装饰者类,Application 是在 createBaseContextForActivity 方法中,通过 ContextImpl 的静态方法 createActivityContext 获得一个 ContextImpl 的实例对象,并通过 setOuterContext 方法将两者建立关联;Activity 是通过 handleLaunchActivity 方法设置的 ContextImpl 实例,这个方法会获取到一个Activity对象,在performLaunchActivity函数中会调用该activity的attach方法,这个方法把一个ContextImpl对象attach到了Activity中。
UML图理解:
装饰者模式共有四大角色:
Component:抽象组件
可以是一个接口或者是抽象类,其充当的就是被装饰的原始对象,用来定义装饰者和被装饰者的基本行为。
ConcreteComponent:组件具体实现类
该类是 Component 类的基本实现,也是我们装饰的具体对象。
Decorator:抽象装饰者
装饰组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。当然,如果是装饰逻辑单一,只有一个的情况下我们可以忽略该类直接作为具体的装饰者。
ConcreteDecoratorA 和 ConcreteDecoratorB:装饰者具体实现类
对抽象装饰者的具体实现。
代码演示:
借助去麦当劳购买汉堡的例子,不同的客户有不同的需求,有的需要加青菜,有的需要加牛排等等,为了满足不同客户的需求,可以使用装饰者模式来实现。
汉堡基类(被装饰者):
package com.gcc.designmode.decorator;
/**
* 汉堡基类(被装饰者)
* @author gcc
*
*/
public abstract class Humburger {
protected String name;
public String getName(){
return name;
}
public abstract double getPrice();
}
被装饰者初始化:
package com.gcc.designmode.decorator;
/**
* 被装饰者初始状态
* @author gcc
*
*/
public class ChickenBurger extends Humburger{
public ChickenBurger() {
name = "鸡腿堡";
}
@Override
public double getPrice() {
// TODO Auto-generated method stub
return 10;
}
}
装饰者:
package com.gcc.designmode.decorator;
/**
* 配料的基类(装饰者)
* @author gcc
*
*/
public abstract class Condiment extends Humburger{
public abstract String getName();
}
装饰者实现类:
package com.gcc.designmode.decorator;
/**
* 加生菜(装饰者实现第一层)
* @author gcc
*
*/
public class Lettuce extends Condiment{
private Humburger humburger;
public Lettuce(Humburger humburger) {
this.humburger = humburger;
}
@Override
public String getName() {
return humburger.getName()+"加生菜";
}
@Override
public double getPrice() {
// TODO Auto-generated method stub
return humburger.getPrice()+1.5;
}
}
package com.gcc.designmode.decorator;
/**
* 加辣椒(装饰者实现第二层)
* @author gcc
*
*/
public class Chilli extends Condiment{
private Humburger humburger;
public Chilli(Humburger humburger) {
this.humburger = humburger;
}
@Override
public String getName() {
return humburger.getName()+"加辣椒";
}
@Override
public double getPrice() {
return humburger.getPrice();
}
}
测试类:
package com.gcc.designmode.decorator;
/**
* 测试类(购买汉堡)
* @author gcc
*
*/
public class Test {
public static void main(String[] args) {
Humburger humburger = new ChickenBurger();
System.out.println(humburger.getName()+" 价钱:"+humburger.getPrice());
Lettuce lettuce = new Lettuce(humburger);
System.out.println(lettuce.getName()+" 价钱:"+lettuce.getPrice());
Chilli chilli = new Chilli(humburger);
System.out.println(chilli.getName()+" 价钱:"+chilli.getPrice());
Chilli chilli2 = new Chilli(lettuce);
System.out.println(chilli2.getName()+" 价钱:"+chilli2.getPrice());
}
}
作者:scgyus(转载请说明出处)