GoF定义:对一个对象动态地添加额外功能。装饰器提供了一种替代子类实现的方法,灵活地扩展类的功能。(Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.)
进一步说明:使用装饰器是为了给现有的类方法增加额外功能。但装饰器模式不改写(modify)方法,而是扩展(extends)方法。一旦继承父类并改写某个方法,那就不叫装饰器了。
装饰器这个名词很形象地描述了这样一个场景:增加的功能只是装饰品,是附属在实体类之上的,被装饰的实体类的结构不能被改变(包括继承并改变)。
举例:例如我们有一位Y教授,他本质上是一个人类,具有普通人的共性。但他出席不同的活动就会有不同的打扮和装饰。例如去做国际报告,那就要穿一身正装讲一口流利的英语,说一些谁都没听过的东西,以便把台下的人忽悠的一愣一愣;如果他去请朋友吃饭,就会打扮时尚,讲话引经据典风趣幽默。我们用代码来实现以上的描述。显然,不同场合下的Y叫兽是同一个人,我们不能继承出一个新的人出来完全改写他的属性,而是使用装饰器,扩展他的属性。
public class Main {
public static void main(String[] args) {
ProfessorY prof = new ProfessorY();
AbstractDecoratorProfessorY profAtCon = new ProfessorYAtConference();
profAtCon.setProfessorY(prof);
profAtCon.getDescription();
AbstractDecoratorProfessorY proAtDinner = new ProfessorYAtDinner();
proAtDinner.setProfessorY(prof);
proAtDinner.getDescription();
}
}
abstract class AbstractProfessorY {
abstract void getDescription();
}
// 被装饰的实体类
class ProfessorY extends AbstractProfessorY {
@Override
void getDescription() {
System.out.println("I am a human being.");
}
}
// 装饰器的抽象类,给予此,我们将扩展出2种不同的场景
abstract class AbstractDecoratorProfessorY extends AbstractProfessorY {
ProfessorY professor;
// 这里是关键,我们加载实体类对象,在此基础上扩展。
void setProfessorY(ProfessorY p) {
this.professor = p;
}
@Override
void getDescription() {
if (professor != null) {
professor.getDescription();
}
}
}
// 为开会而装饰
class ProfessorYAtConference extends AbstractDecoratorProfessorY {
@Override
void getDescription() {
System.out.println("-- Conference decorator --");
super.getDescription();
actingAtConference();
}
void actingAtConference() {
System.out.println("I wear a suit, speaking english and talk something no one knows!");
}
}
// 为聚会而装饰
class ProfessorYAtDinner extends AbstractDecoratorProfessorY {
@Override
void getDescription() {
System.out.println("-- Dinner decorator --");
super.getDescription();
actingAtDinnerParty();
}
void actingAtDinnerParty() {
System.out.println("I am casual wearing and have fun!");
}
}
运行结果:
实现关键:
× 装饰器里不继承实体类对象,而是在实体类对象的前后添加额外功能。
后记:
装饰器相比与继承的优点在于,一个装饰器能装饰不同的类,只要这些被装饰的类具有相同的接口即可(即实现了一开始所说的“动态添加功能”)。而如果要用继承来实现,每一个类都要分别继承并重写方法。