1.定义
装饰模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
简单来说:装饰模式式动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。
2.概述
在许多设计中,可能需要改进类的某个对象的功能,而不是该类创建的全部对象。 例如,鸟类的实例(麻雀)能连续飞行100米,如果用鸟类创建了5只麻雀对象,那么这5只麻雀都能连续飞行100米。假设我们想让其中一只麻雀能够连续飞行150米(大于100),那么应当怎么做呢?我们不想通过修改麻雀类的代码使得麻雀类创建的麻雀都能连续飞行150米,这也不符合我们的初衷:改进类的某个对象的功能。
一种比较好的方式就是给某只麻雀装上只能电子翅膀。智能电子翅膀可以死的麻雀不适用自己的翅膀就能飞行50米。那么一只安装了这种智能电子翅膀的麻雀就能飞行150了,因为麻雀首先使用自己的翅膀飞行100米,然后在使用智能电子翅膀飞行50米,一共150米。
3.应用场景
1、扩展一个类的功能。
2、动态增加功能,动态撤销。
4.模式的结构和使用
装饰模式的结构中包括四种角色:
1.抽象组件(Component):抽象组件是一个抽象类。抽象组件定义了“被装饰者”需要进行“装饰”的方法;
2.具体组件(ConcreteComponent):具体组件是抽象组件的一个子类,具体组件的实例称之为“被装饰者”;
3.装饰(Decorator):装饰也是抽象组件的一个子类,但但装饰还包含一个抽象组件声明的变量以保存“被装饰者”的引用。装饰可以是抽象类也可以是一个非抽象类,如果是非抽象类,那么该类的实例就是“装饰者”;
4.具体装饰(ConcreteDecorator):具体装饰是装饰的一个非抽象子类,具体装饰的实例称作装饰者。
1.装饰模式的UML类图
前面概述所提到的麻雀就是类图中的ConcreteComponent角色的实例,安装了一对智能电子翅膀的麻雀是ConcreteDecorator角色的实例。
2.结构的描述
假设系统中有一个Bird抽象类以及Bird类的一个子类:Sparrow。Sparrow类实现了Bird类的fly方法,使得Sparrow类创建的对象(麻雀)调用fly方法能连续飞行100米;
现在,用户需要两只鸟,无论那只鸟都可以,但必须分别能够连续飞行150米和200米。显然,现有的系统无法向两只用户提供这样的Bird对象,所以需要修改现有的系统。我们发现,如果使用装饰模式,不必修改原来的代码,只需要在系统中添加“装饰”,该系统将可以创建出用户需要的鸟。具体设计如下所示:
1.抽象组件
在抽象组件中定义了抽象的fly(飞行)方法;
Bird.java
package com.xing.decorator;
public abstract class Bird {
public abstract int fly();
}
2.具体组件
定义具体组件Sparrow,在里面继承抽象组件Bird类,并实现fly方法;
Sparrow.java
package com.xing.decorator;
public class Sparrow extends Bird{
public final int DISTANCE=100;
@Override
public int fly() {
return DISTANCE;
}
}
3.装饰
装饰类同样是抽象类,并且继承Bird,在里面实现默认构造函数和有参构造函数,并且有Bird类的引用;
Decorator.java
package com.xing.decorator;
public abstract class Decorator extends Bird{
protected Bird bird;
public Decorator() {
}
public Decorator(Bird bird) {
this.bird = bird;
}
}
4.具体装饰
根据具体的问题,具体装饰经常委托被装饰者调用相应的方法;
package com.xing.decorator;
public class SparrowDecorator extends Decorator{
public final int DISTANCE=50;
public SparrowDecorator(Bird bird) {
super(bird);
}
@Override
public int fly() {
int distance=0;
distance=bird.fly()+eleFly();//委托被装饰者bird调用fly方法,然后在调用eleFly()
return distance;
}
private int eleFly(){
return DISTANCE;//eleFly方法能够飞50米
}
}
5.主程序测试
package com.xing.decorator;
public class Application {
public void needBird(Bird bird){
System.out.println("这只鸟能够飞行"+bird.fly()+"米");
}
public static void main(String[] args) {
Application application=new Application();
Bird sparrow=new Sparrow();//sparrow能够飞行100米
Bird sparrowDecorator1=new SparrowDecorator(sparrow);//sparrowDecorator1能飞行100+50米
Bird sparrowDecorator2=new SparrowDecorator(sparrowDecorator1);sparrowDecorator1能飞行150+50米
application.needBird(sparrowDecorator1);
application.needBird(sparrowDecorator2);
}
}
6.测试结果展示
5.装饰模式的优点
1.被装饰者和装饰者是松耦合关系。
2.装饰模式满足开闭原则
3.可以使用多个具体装饰来装饰具体组件的实例。