装饰器模式
介绍
装饰器模式(Decorator Pattern)指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰类来包装原有的类,并提供额外的功能。
引入问题
举个例子,某公司拥有一众程序员。
public class Coder() {
public void code() {
System.out.println("会写代码的程序员...");
}
}
现在,业务需要有Java语言code能力的程序员。按照面向对象的设计思想,一般的做法是新增一个JavaCoder类,继承Coder类
public class JavaCoder extends Coder {
public void codeJava() {
System.out.println(" 会使用Java语言....");
}
}
然后,又需要有Go语言code能力的程序员,照例需要新添加一个GoCoder类,继承Coder类
public class GoCoder extends Coder {
public void codeGo() {
System.out.println(" 会使用Go语言....");
}
}
这时,如果现在需要既有Java语言code能力,又有Go语言code能力的程序员,又需要创建一个JavaAndGoCoder类,这样就会导致一旦有需求增加或变更,类数量就会暴增。如果已经存在的类能复用就好了。
解决方案
装饰器模式就是为了解决上述问题而生的。它通过把复杂的功能简单化,分散化,然后在运行期间,根据需要来动态组合。装饰器模式的通用类图如下:
在装饰器模式中一共有以下四种角色
- Component
增加功能时的核心角色。负责定义功能接口。 - ConcreteComponent
实现Component角色所定义的接口。 - Decorator
该角色与Component角色有相同的接口,且在该角色内保存了Component角色。 - ConcreteDecorator
该角色是Decorator角色的具体实现。
以上述程序员的问题为例,我们使用装饰器模式为Coder类动态添加方法
- Coder类(扮演Component角色)
public abstract class Coder {
public abstract void code();
} - ConcreteCoder类(扮演ConcreteComponent角色)
public class ConcreteCoder extends Coder {
@Override
public void code() {
System.out.println("会写代码的程序员...");
}
} - CoderDecorator类(扮演Decorator角色)
public abstract class CoderDecorator extends Coder {
private Coder coder;
public CoderDecorator(Coder coder) {
this.coder = coder;
}
@Override
public void code() {
coder.code();
}
} - JavaCoder类(扮演ConcreteDecorator角色)
public class JavaCoder extends CoderDecorator {
public JavaCoder(Coder coder) {
super(coder);
}
public void codeJava() {
System.out.println("用Java语言写代码...");
}
@Override
public void code() {
super.code();
codeJava();
}
} - GoCoder类(扮演ConcreteDecorator角色)
public class GoCoder extends CoderDecorator {
public GoCoder(Coder coder) {
super(coder);
}
public void codeGo() {
System.out.println("用Go语言写代码...");
}
@Override
public void code() {
super.code();
codeGo();
}
}
此时,当我们需要既有Java语言code能力,又有Go语言code能力的程序员时,只要用CoderDecorator类和CoderDecorator类去装饰ConcreteCoder类就行了,而不需要再新增类。
调用类
public class Client { public static void main(String[] args) { Coder coder = new GoCoder(new JavaCoder(new ConcreteCoder())); coder.code(); } }
输出结果
会写代码的程序员... 用Java语言写代码... 用Go语言写代码...
到此,我们就通过装饰器模式实现了功能的动态增加。
装饰器模式总结
- 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
- 缺点:多层装饰比较复杂。