本篇供个人学习使用,有问题欢迎讨论
装饰者设计模式
一、什么是装饰者设计模式
Decorator Pattern,能够在不修改目标类也不使用继承的情况下,动态地扩展一个类的功能。它是通过创建一个包装对象,也就是装饰者来达到增强目标类的目的的。
装饰者设计模式的实现有两个要求:
-
装饰者类与目标类要实现相同的接口,或继承自相同的抽象类
-
装饰者类中要有目标类的引用作为成员变量,而具体的赋值一般通过带参构造器完成
这两个要求的目的是,在装饰者类中的方法可以调用目标类的方法,以增强这个方法。而增强的这个方法是通过重写的方式进行的增强,所以要求实现相同的接口或继承相同的抽象类。
在装饰者设计模式中,装饰者类一般是不对目标类进行增强的。装饰者类作为一个基类,具体的装饰者继承自这个基类,对目标类进行具体的、单功能的增强。这样做的好处是,在很方便的情况下可以实现多重地、组合式地增强。
二、装饰者设计模式的用法
1、基本用法
如实现对一个字符串的大写功能:
ISomeService(接口):
public interface ISomeService {
String doSome();
}
SomeServiceImpl(目标类):
public class SomeServiceImpl implements ISomeService {
public String doSome() {
return "abc";
}
}
SomeServiceDecorator(装饰者):
public class SomeServiceDecorator implements ISomeService {
private ISomeService target; //目标对象
//通过带参构造器传入目标对象
public SomeServiceDecorator(ISomeService target) {
this.target = target;
}
public String doSome() {
return target.doSome().toUpperCase();
}
}
测试:
public class Test02 {
public static void main(String[] args) {
//创建目标对象
ISomeService target = new SomeServiceImpl();
//使用目标对象作为参数,创建装饰者
ISomeService service = new SomeServiceDecorator(target);
//使用装饰者的业务方法
String result = service.doSome();
System.out.println("result = " + result);
}
}
输出结果:
2、高级用法
如实现对一个字符串的大写和忽略前后空白的功能:
ISomeService(接口):
public interface ISomeService {
String doSome();
}
SomeServiceImpl(目标类):
public class SomeServiceImpl implements ISomeService {
public String doSome() {
return " abc ";
}
}
SomeServiceWrapper(基类):
- 要有无参构造器
- 不对目标类的目标方法进行任何增强
public class SomeServiceWrapper implements ISomeService {
private ISomeService target; //目标对象
//无参构造
public SomeServiceWrapper() {
}
//通过带参构造器传入目标对象
public SomeServiceWrapper(ISomeService target) {
this.target = target;
}
//调用目标类的目标方法,但不对其进行任何的增强
public String doSome() {
return target.doSome();
}
}
TrimDecorator(具体装饰者):
- 要继承自装饰者基类
- 要有带参构造器
- 具体装饰者只对装饰者基类业务方法进行某一种单一的增强
public class TrimDecorator extends SomeServiceWrapper {
public TrimDecorator() {
}
public TrimDecorator(ISomeService target) {
super(target);
}
//重写基类的业务方法
public String doSome() {
//调用基类的业务方法,并对其进行增强
return super.doSome().trim();
}
}
ToUpperCaseDecorator(具体装饰者):
public class ToUpperCaseDecorator extends SomeServiceWrapper {
public ToUpperCaseDecorator() {
}
public ToUpperCaseDecorator(ISomeService target) {
super(target);
}
public String doSome() {
return super.doSome().toUpperCase();
}
}
测试:
public class Test02 {
public static void main(String[] args) {
//创建目标对象
ISomeService target = new SomeServiceImpl();
//使用目标对象作为参数,创建装饰者
ISomeService service = new TrimDecorator(target);
//将第一次增强过的结果作为第二次增强的参数出现,形成“装饰者链”
ISomeService service2 = new ToUpperCaseDecorator(service);
//使用装饰者的业务方法
String result = service2.doSome();
System.out.println("result = " + result);
}
}
输出结果(使用“装饰者”之前):
使用“装饰者”之后:
三、静态代理设计模式
ISomeService(接口):
public interface ISomeService {
String doSome();
}
SomeServiceImpl(目标类):
public class SomeServiceImpl implements ISomeService {
public String doSome() {
return " abc ";
}
}
OtherServiceProxy(静态代理类):
public class OtherServiceProxy implements ISomeService {
private ISomeService target;
//在无参构造器中创建目标对象
public OtherServiceProxy() {
target = new SomeServiceImpl();
}
public String doSome() {
return target.doSome().toUpperCase();
}
}
测试:
public class Test03 {
public static void main(String[] args) {
ISomeService service = new OtherServiceProxy();
String result = service.doSome();
System.out.println("result = " + result);
}
}
输出结果:
四、装饰者设计模式与静态代理设计模式的对比
静态代理类与装饰者间的共同点
- 都要实现与目标类相同的业务接口
- 这两个类中都要声明目标对象
- 都可以在不修改目标类的前提下增强目标方法
静态代理类与装饰者间的区别
-
使用目的不同
装饰者的使用目的是:就是增 强目标对象
静态代理的使用目的是:是为保护和隐藏目标对象 -
对于目标对象的获取方式不同
装饰者类中目标对象的获取:通过带参构造器传入
静态代理中目标对象的获取:在无参构造器中直接创建 -
功能增强的实现者不同
装饰者设计模式中存在装饰者基类,其并不真正实现增强,而是=由具体的装饰者进行功能增强的,所以存在一个 “ 装饰者链 “ 的概念
静态代理设计模式中一般不存在父子类的关系,具体的增强,就是由代理类完成,无需其子类完成,所以不存在 “ 链 ” 的概念