变更原因
上次我们将一个通用常量类文件拆分成责任链模式中的各个节点,每个节点保存当前类型的常量数据,比如BigDecimal常量放在BigGlobal类中,String常量放在StrGlobal类中,然后创建责任链工厂,在类加载的时候将所有的常量类放到责任链中,调用的时候使用统一的getValue()方法调用,如果找不到当前key的数据,就往下传递,直到找到或者抛出异常,虽然逻辑上没有问题,但是在上次的代码中一个最大的问题是每个责任链模式的节点类都要自己实现getValue()方法,这显然不是我们想要的,出于简单考虑,我们肯定希望节点类中只有常量数据才是最舒服的,所以我在上次的代码基础上,做了些改动,将获取key值的方法放到工厂类中去解决。
上一版本的地址
代码演示
/**
* 父级抽象类
*/
public abstract class GlobalHandler {
protected GlobalHandler global;
protected Class<? extends GlobalHandler> globalClass;
protected Class<?> typeClass;
protected GlobalHandler setGlobal(GlobalHandler global, Class<?> typeClass) {
global.setGlobalClass(global.getClass());
global.setTypeClass(typeClass);
this.global = global;
return this.global;
}
public void setGlobalClass(Class<? extends GlobalHandler> globalClass) {
this.globalClass = globalClass;
}
public Class<?> getTypeClass() {
return typeClass;
}
public void setTypeClass(Class<?> typeClass) {
this.typeClass = typeClass;
}
}
/**
* 现在头节点中不需要实现任何方法
*/
public class HeadGlobal extends GlobalHandler {
}
/**
* 尾节点需要处理找不到数据时抛出的异常
*/
public class TailGlobal extends GlobalHandler {
public Object getValue(String name) {
throw new RuntimeException("当前 name[" + name + "] 没有具体的 常量 处理");
}
public <T> T getValue(String name, Class<T> calzz) {
throw new RuntimeException("当前 name[" + name + "] 没有具体的 常量 处理");
}
}
/**
* 数据节点不需要再实现getValue()方法,而是只需要放常量数据
*/
public class BigGlobal extends GlobalHandler {
private final BigDecimal BIG_ZERO = BigDecimal.ZERO;
private final BigDecimal BIG_ONE = BigDecimal.ONE;
private final BigDecimal BID_ONE_HUNDRED = NumberUtil.toBigDecimal("100");
}
/**
* 数据节点不需要再实现getValue()方法,而是只需要放常量数据
*/
public class NumGlobal extends GlobalHandler {
public final Integer NUM_INT_ZERO = 0;
}
以上代码对比之前的数据,看起来要舒服多了
通用常量处理类
public class GlobalUtil {
private final GlobalHandler head;
private GlobalUtil() {
head = new HeadGlobal();
GlobalHandler strGlobal = new StrGlobal();
GlobalHandler numGlobal = new NumGlobal();
GlobalHandler bigGlobal = new BigGlobal();
GlobalHandler tail = new TailGlobal();
head.setGlobal(strGlobal, String.class)
.setGlobal(numGlobal, Integer.class)
.setGlobal(bigGlobal, BigDecimal.class)
.setGlobal(tail, TailGlobal.class);
}
public static <T> T value(String name, Class<T> clazz) {
return getInstance().getValue(name, clazz);
}
public static Object value(String name) {
return getInstance().getValue(name);
}
public static GlobalUtil getInstance() {
return SingletonGlobalHandler.INSTANCE;
}
public Object getValue(String name) {
GlobalHandler handler = head.global;
while (true) {
try {
return getValue(name, handler.typeClass);
} catch (RuntimeException e) {
handler = handler.global;
}
}
}
public <T> T getValue(String name, Class<T> clazz) {
try {
GlobalHandler handler = head;
while (true) {
if (Objects.isNull(handler.getTypeClass())
|| !Objects.equals(handler.getTypeClass(), clazz)) {
handler = handler.global;
continue;
}
if (handler.getClass().equals(TailGlobal.class)) {
throw new RuntimeException("不存在此类型的通用常量【" + clazz.getName() + "】");
}
return (T) getValue(name, handler);
}
} catch (NoSuchFieldException ne) {
throw new RuntimeException("当前 name[" + name + "] 没有具体的 常量 处理");
}
}
public Object getValue(String name, GlobalHandler handler) throws NoSuchFieldException {
Field field;
try {
field = handler.globalClass.getDeclaredField(name);
field.setAccessible(true);
return field.get(handler);
} catch (NoSuchFieldException | IllegalAccessException ne) {
throw new RuntimeException("当前 name[" + name + "] 没有具体的 常量 处理");
}
}
private static class SingletonGlobalHandler {
private static final GlobalUtil INSTANCE = new GlobalUtil();
}
}
HowToUse
public class HowToUse {
private static final Logger log = Logger.getLogger("HowToUse");
public static void main(String[] args) {
// 可以获取指定类型的常量
BigDecimal zero = GlobalUtil.value("BIG_ONE", BigDecimal.class);
// 获取未知类型的常量
Object intZero = GlobalUtil.value("NUM_INT_ZERO");
log.info(String.valueOf(zero)); // BigDecimal 1
log.info(String.valueOf(intZero));// Object 0
}
}
以上代码很有脱裤子放屁的嫌疑
其实当数据量不大时,我们只需要给常量类设置成static,直接调用即可(而且可以明确常量类型)
public class NumGlobal extends GlobalHandler {
public static final Integer NUM_INT_ZERO = 0;
}
HowToUse
public static void main(String[] args) {
log.info(String.valueOf(NumGlobal.NUM_INT_ZERO)); // 0
}
虽然本人也觉得上面的【使用责任链模式维护通用常量】有点儿脑残且无用,但是在写以上代码时,确实让本人对责任链模式的理解更加通透了,希望它也能帮各位理解这个设计模式。