二、定义

装饰模式是在不必改变原类和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象

三、使用场景

  1. 需要在运行时动态的给一个对象增加额外的职责时候
  2. 需要给一个现有的类增加职责,但是又不想通过继承的方式来实现的时候(应该优先使用组合而非继承),或者通过继承的方式不现实的时候(可能由于排列组合产生类爆炸的问题)。

四、 UML图

假设我们有一个原味咖啡的类 OriginalCoffee​, 目前的需求就是要动态的给这个类的一些实例增加一些额外功能,此处就是动态的对某些咖啡制作过程增加新的流程,例如加奶,加糖,而有的咖啡却保持原味不变。

java装饰器模式_java

ICoffee接口,里面有一个制作咖啡的接口方法makeCoffee()。要进行装饰的类 OriginalCoffee装饰者基类CoffeeDecorator(一般为抽象类)实现了此接口。

CoffeeDecorator类里面持有一个ICoffee引用,我们第一步会把要装饰那个原始对象赋值给这个引用,那样在装饰者类中才可以调用到那个被装饰的对象的方法。

MilkDecoratorSugarDecorator

五、咖啡加奶加糖的例子具体实现

第一步:先声明一个原始对象的接口

public interface ICoffee {
void makeCoffee();
}

第二步:构建我们的原始对象,此处为原味咖啡对象,它实现了​​ICoffee​​接口。


public class OriginalCoffee implements ICoffee{
@Override
public void makeCoffee() {
System.out.println("原味咖啡");
}
}

第三步:构建装饰者抽象基类,它要实现与原始对象相同的接口​ICoffee​​,其内部持有一个​ICoffee​类型的引用,用来接收被装饰的对象。

public abstract class CoffeeDecorator implements ICoffee{
private ICoffee coffee;

public CoffeeDecorator(ICoffee coffee){
this.coffee = coffee;
}

@Override
public void makeCoffee() {
coffee.makeCoffee();
}
}

第四步:构建各种装饰者类,他们都继承至装饰者基类 ​​CoffeeDecorator​​。此处生成了两个,一个是加奶的装饰者,另一个是加糖的装饰者。

MilkDecorator

package milk;

public class MilkDecorator extends CoffeeDecorator{
public MilkDecorator(ICoffee coffee) {
super(coffee);
}

@Override
public void makeCoffee() {
super.makeCoffee();
addMilk();
}

private void addMilk(){
System.out.println("加奶");
}
}

SugarDecorator

public class SugarDecorator extends CoffeeDecorator{
public SugarDecorator(ICoffee coffee) {
super(coffee);
}

@Override
public void makeCoffee() {
super.makeCoffee();
addSugar();
}

private void addSugar(){
System.out.println("加糖");
}
}

第五步:客户端使用

public static void main(String[] args) {
// 原味咖啡
ICoffee coffee = new OriginalCoffee();
coffee.makeCoffee();

// 加奶的咖啡
coffee = new MilkDecorator(coffee);
coffee.makeCoffee();

// 先加奶,后加糖的咖啡
coffee = new SugarDecorator(coffee);
coffee.makeCoffee();

}

可以从客户端调用代码看出,装饰者模式的精髓在于动态的给对象增减功能

六、字符串处理的场景

6.1 背景

mock平台,对字符串处理。如下字符串

response: '{"key11":"${random:id:6}","key2":"${random:str:10}","count":3,"person":[{"id":${hook:id}},"name":"张三"},{"id":2,"name":"李四"}],"object":{"id":1,"msg":"对象里的对象"}}'

将 ${random:id:6} 替换成,6位的数字。

将 ${random:str:10}替换成,10位的字符串。

使用装饰器模式,依次对这一串字符进行装饰。

6.2 装饰器的实现

1、先写基类的接口IDecorator

对字符串的处理,输入是字符串,输出也是字符串,这里用的泛型。

public interface IDecorator<T> {
T decorate(T data);
}

 2、装饰器的基类BaseResponseDecorator

这里不仅仅定义了装饰的方法,还定义了装饰的逻辑。将来我们通过manager将所有的装饰类串成一串。

public abstract class BaseResponseDecorator<T> implements IDecorator<T>{
private BaseResponseDecorator<T> decorator;

// 构造器
public BaseResponseDecorator(BaseResponseDecorator<T> decorator) {
this.decorator = decorator;
}

// 自己装饰的方法,重写这个方法
public abstract T onDecorator(T t);

// 整体调用的逻辑
public T decorate(T t){
// 先判断,当前属性是否为空
if(decorator != null){
// 不为空,先让下一节decorator装饰
t = decorator.decorate(t);
// 再自己装饰一次,一共装饰了2次
return onDecorator(t);
}
// 为空,就调用自己的装饰方法。只装饰一次
return onDecorator(t);
}

}

3、对数字的处理RandomIdDecorator 

import com.example.mockserver.util.RandomUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RandomIdDecorator extends BaseResponseDecorator<String>{

private static final Pattern PATTERN = Pattern.compile("\\$\\{random:id:(\\d+?)\\}");
// 构造器
public RandomIdDecorator(BaseResponseDecorator<String> decorator) {
super(decorator);
}

@Override
public String onDecorator(String data) {
Matcher matcher = PATTERN.matcher(data);
while (matcher.find()){
String replaceStr = matcher.group(0);
int size = Integer.parseInt(matcher.group(1));
// 替换
data = StringUtils.replace(data,replaceStr, RandomUtil.randomNum(size));
}
return data;
}

}

4、对字符串的处理RandomStrDecorator

import com.example.mockserver.util.RandomUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RandomStrDecorator extends BaseResponseDecorator<String>{

private static final Pattern PATTERN = Pattern.compile("\\$\\{random:str:(\\d+?)\\}");
// 构造器
public RandomStrDecorator(BaseResponseDecorator<String> decorator) {
super(decorator);
}

@Override
public String onDecorator(String data) {
Matcher matcher = PATTERN.matcher(data);
while (matcher.find()){
String replaceStr = matcher.group(0);
int size = Integer.parseInt(matcher.group(1));
// 替换
data = StringUtils.replace(data,replaceStr, RandomUtil.randomStr(size));
}
return data;
}

}

5、 对多个装饰器的管理DecoratorManager

package com.example.mockserver.decorator;

public class DecoratorManager {
// 属性
private IDecorator<String> decorator;

// 构造器,私有,不能被new
private DecoratorManager(){
decorator = new RandomIdDecorator(new RandomStrDecorator(null));
}

// ClassHolder属于静态内部类,在加载类Demo03的时候,只会加载内部类ClassHolder,
// 但是不会把内部类的属性加载出来
private static class ClassHolder{
// 这里执行类加载,是jvm来执行类加载,它一定是单例的,不存在线程安全问题
// 这里不是调用,是类加载,是成员变量
private static final DecoratorManager holder =new DecoratorManager();

}

public static DecoratorManager of(){//第一次调用getInstance()的时候赋值
return ClassHolder.holder;
}

public String doPack(String response){
return decorator.decorate(response);
}


}

6、调用

String packResponse  = DecoratorManager.of().doPack(finalResponse);