概括
动态地给对象添加一些额外的职责。就功能来说装饰模式相比子类更为灵活。
概述
在许多设计中,可能需要改进类的某个类的某个对象的某个功能,而不是该类创建的所有对象。例如 麻雀类的实例(麻雀)可以飞行100米 ,但有一只麻雀安装了特殊的装置 可以飞行150米。
装饰模式是动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。“具体组件“类与“具体装饰“类是该模式中最重要的两个角色。前者的实例被称为“被装饰者” 后者被称为“装饰者”。“具体装饰”类需要包括“具体组件”类的一个实例的引用,以便装饰 “被装饰者”。
注:装饰模式中非常重要的一点是:“具体组件”和“装饰”都是“抽象组件”的子类 ,则“抽象组件”声明的对象既可以存放“被装饰者”的引用也可以存放“装饰者”的引用。对用户而言 “装饰者”所实现抽象组件中的方法是“被装饰者”相应的方法的改进或修正。因此,用户如果需要调用“被装饰者”原始方法就让“抽象组件”声明的对象存放“被装饰者”的引用,反之,则存放“装饰者”的引用。
UML类图
装饰模式的四种角色
- 抽象组件(Component): 抽象组件是一个抽象类,定义了“被装饰者”需要进行“装饰”的方法。
- 具体组件(ConcreteComponent):具体组件是抽象组件的一个子类,具体组件的实例被称作“被装饰者”。
- 装饰(Decorator):装饰也是抽象组件的一个子类,但装饰还包含一个抽象组件声明的变量以便保存“被装饰者”的引用。装饰可以是抽象类也可以是非抽象类,如果是非抽象类,那么该类的实例被称作“被装饰者”。
- 具体装饰(ConcreteDecotator):具体装饰是装饰的一个非抽象子类,具体装饰的实例称作“装饰者”。
例子:从冰箱中拿出大象
Pattern.java
public interface Pattern {
public void doGet();
}
Decorator.java
public abstract class Decorator implements Pattern{
private Pattern pattern;
Decorator(Pattern pattern){
this.pattern = pattern;
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
public void doGet(){
pattern.doGet();
}
}
装饰器实例
public class DecoratorOne extends Decorator{
DecoratorOne(Pattern pattern) {
super(pattern);
// TODO Auto-generated constructor stub
}
public void openFrige(){
System.out.println("第一步 打开冰箱");
}
@Override
public void doGet(){
super.doGet();
openFrige();
}
}
public class DecoratorTwo extends Decorator{
DecoratorTwo(Pattern pattern) {
super(pattern);
// TODO Auto-generated constructor stub
}
public void getElephant(){
System.out.println("第二步 拿出大象");
}
@Override
public void doGet(){
super.doGet();
getElephant();
}
}
public class DecoratorThree extends Decorator{
DecoratorThree(Pattern pattern) {
super(pattern);
// TODO Auto-generated constructor stub
}
public void closeFridge(){
System.out.println("第三步 关上冰箱");
}
@Override
public void doGet(){
super.doGet();
closeFridge();
}
}
被装饰者
public class Person implements Pattern{
@Override
public void doGet() {
// TODO Auto-generated method stub
System.out.println("我想把冰箱里的大象拿出来");
}
}
Test.java
public class Test {
public static void main(String[] args) {
Pattern pattern = new Person();
Decorator decorator = new DecoratorThree
(new DecoratorTwo(new DecoratorOne(pattern)));
decorator.doGet();
}
}
运行结果:
我想把冰箱里的大象拿出来
第一步 打开冰箱
第二步 拿出大象
第三步 关上冰箱
要点:
- 如上述例子 ,装饰者也可以被装饰 成为被装饰者,经过一层层装饰 达到类似于过滤链的效果;Decorator抽象类中,持有Pattern接口,需要改进或修正的方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
- 具体被装饰者类,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。
装饰者模式的设计原则为:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。所以:扩展体现在继承、修改在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则,这是自己理解的装饰者模式。