装饰者模式
1、概念
在不改变原类文件以及不使用继承的情况下,动态地将责任附加到对象上,从而实现动态拓展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比子类更为灵活。
2、角色及图例
- Component(抽象组件):通常是一个抽象类或者一个接口,定义了属性或者方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类来实现特定的功能,它约束了整个继承树的行为。比如说,如果Component代表人,即使通过装饰也不会使人变成别的动物。
- ConcreteComponent(具体组件):是Component的子类,抽象装饰者能给他新增职责,实现了相应的方法,它充当了“被装饰者”的角色。
- Decorator(抽象装饰者):也是Component的子类,持有一个抽象组件对象的实例,并定义一个与抽象组件一致的接口。。比如说,Decorator代表衣服这一类装饰者,那么它的子类应该是T恤、裙子这样的具体的装饰者。
- ConcreteDecorator(具体装饰者):是Decorator的子类,是具体的装饰者,给内部持有的具体组件增加具体的职责;由于它同时也是Component的子类,因此它能方便地拓展Component的状态(比如添加新的方法)。每个装饰者都应该有一个实例变量用以保存某个Component的引用,这也是利用了组合的特性。在持有Component的引用后,由于其自身也是Component的子类,那么,相当于ConcreteDecorator包裹了Component,不但有Component的特性,同时自身也可以有别的特性,也就是所谓的装饰。
3、代码演示
//抽象组件,可以是抽象类,也可以是接口
public abstract class Person {
String description = "Unkonwn";
public String getDescription()
{
return description;
}
public abstract double cost(); //子类应该实现的方法
}
//具体组件
public class Adult extends Person {
public Adult() {
description = "今天的穿搭:";
}
@Override
public double cost() {
//什么都没买,不用钱
return 0;
}
}
//抽象装饰者,可以设置多个
public abstract class ClothingDecorator extends Person {
public abstract String getDescription();
}
//抽象装饰者
public abstract class ShoesDecorator extends Person {
public abstract String getDescription();
}
//具体装饰者,可以设置多个
public class Suit extends ClothingDecorator {
//用实例变量保存Person的引用
private Person person;
public Suit(Person person)
{
this.person = person;
}
@Override
public String getDescription() {
return person.getDescription() + "通勤套装,";
}
@Override
public double cost() {
//实现了cost()方法,并调用了person的cost()方法,目的是获得所有累加值
return 100 + person.cost();
}
}
//具体装饰者
public class Shoes extends ShoesDecorator {
private Person person;
public Shoes(Person person) {
this.person = person;
}
@Override
public String getDescription() {
return person.getDescription() + "黑色中跟通勤鞋,";
}
@Override
public double cost() {
//实现了cost()方法,并调用了person的cost()方法,目的是获得所有累加值
return 75 + person.cost();
}
}
public static void main(String[] args) {
Person person = new Adult();
person = new Suit(person);
person = new Shoes(person);
System.out.println(person.getDescription() + "共花费¥ " +person.cost());
}
4、模式特点
-
装饰者(decorator)和被装饰(扩展)的对象有着相同的超类(supertype)。
-
我们可以用多个装饰者去装饰一个对象。
-
我们可以用装饰过的对象替换代码中的原对象,而不会出问题(因为他们有相同的超类)。
-
装饰者可以在委托(delegate,即调用被装饰的类的成员完成一些工作)被装饰者的行为完成之前或之后加上他自己的行为。
-
一个对象能在任何时候被装饰,甚至是运行时。
5、使用场景
-
需要扩展一个类的功能,或给一个类添加附加职责。
-
需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
-
需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
-
当不能采用生成子类的方法进行扩充时。可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
6、优缺点
优点:
- Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点:
-
装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
-
装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。