责任链模式优化通用常量 (一)

85 阅读3分钟

不懂寒暄,废话少说先看代码

image.png

这段代码一开始是给我们的商城系统中,订单模块使用的通用常量类的集合,起初还只有一小部分,所以使用起来并没有觉得很复杂,寻找一个常量时往往可以很快找到,但是随着笔者决定对公司代码review时,突然发现系统中通用常量到处都是,本着让代码变得干净漂亮的原则,决定对所有具有意义的魔法常量进行通用常量设置,结果搞了一天,突然发现原本小而美的常量类,变得臃肿而难用,再去找寻一个常量时,根本不知道自己有没有写过,而且常量的类型乱七八糟,有数组,有字符串,有Long,有Integer,还有布尔值等等...

当他们都在一个类中时,无法进行有效的分类,所以笔者想着能不能分开处理这些常量呢?比如字符串就跟字符串放一起,数组常量跟数组常量放一起,然后用一个类去管理他们?

灵感来源于昨天晚上逛掘金时看到了这篇文章,# 去掉 if...else 的七种绝佳之法... 里面详细介绍了七种去掉if...else的方式,而让我第一时间想到的是,能不能用【责任链模式】来处理我的问题?

创建一个工厂和处理类,不同类型的常量都被处理类管理,在处理类中有个通用的方法,只需要传各个类的Field的name,就可以获取它的值?好像可以,说干就干!

1,创建通用常量处理器

public abstract class GlobalHandler {

    protected GlobalHandler global;

    protected GlobalHandler setGlobal(GlobalHandler global){
        this.global = global;
        return this.global;
    }

    public abstract Object getValue(String name) throws NoSuchFieldException;
}

2,创建头节点

public class HeadGlobal extends GlobalHandler {

    @Override
    public Object getValue(String name) throws NoSuchFieldException {
        String globalName = Optional.ofNullable(name)
                .filter(CharSequenceUtil::isNotEmpty)
                .orElseThrow(() -> new BizException("常量NAME不能为空"));
       return global.getValue(globalName);
    }
}

3,创建尾节点

public class TailGlobal extends GlobalHandler {

    @Override
    public Object getValue(String name) {
        throw new BizException("当前 name[" + name + "] 没有具体的 常量 处理");
    }
}

4,创建不同类型的常量容器

public class BigGlobal extends GlobalHandler {
    
    public final BigDecimal BIG_ZERO = BigDecimal.ONE;

    @Override
    public Object getValue(String name) throws NoSuchFieldException{
        Class<?> bigClazz = BigGlobal.class;
        Field field;
        try{
            field = bigClazz.getDeclaredField(name);
            return field.get(this);
        }catch (NoSuchFieldException | IllegalAccessException ne){
            return global.getValue(name);
        }
    }
}
public class NumGlobal extends GlobalHandler {

    public final Integer NUM_INT_ZERO = 0;

    @Override
    public Object getValue(String name) throws NoSuchFieldException {
        Class<?> numClazz = NumGlobal.class;
        Field field;
        try{
            field = numClazz.getDeclaredField(name);
            return field.get(this);
        }catch (NoSuchFieldException | IllegalAccessException ne){
            return global.getValue(name);
        }
    }
}
public class StrGlobal extends GlobalHandler {

    public final String STR_ZERO = "0";

    @Override
    public Object getValue(String name) throws NoSuchFieldException {
        Class<?> strClazz = StrGlobal.class;
        Field field;
        try{
            field = strClazz.getDeclaredField(name);
            return field.get(this);
        }catch (NoSuchFieldException | IllegalAccessException ne){
            return global.getValue(name);
        }
    }

5,创建解析工厂

public class GlobalHandlerFactory {

    private final GlobalHandler head;

    private GlobalHandlerFactory(){
        head = new HeadGlobal();
        GlobalHandler strGlobal = new StrGlobal();
        GlobalHandler numGlobal = new NumGlobal();
        GlobalHandler bigGlobal = new BigGlobal();
        GlobalHandler tail = new TailGlobal();
        head.setGlobal(strGlobal)
            .setGlobal(numGlobal)
            .setGlobal(bigGlobal)
            .setGlobal(tail);
    }

    private static class SingletonGlobalHandler{
        private static final GlobalHandlerFactory instance = new GlobalHandlerFactory();
    }

    public static GlobalHandlerFactory getInstance(){
        return SingletonGlobalHandler.instance;
    }

    public Object getValue(String name) {
        try {
            return head.getValue(name);
        }catch (NoSuchFieldException ne){
            throw new BizException("当前 name[" + name + "] 没有具体的 常量 处理");
        }
    }

至此,已经将上述改造悉数完成,接下来我们写几个测试类看看如何。

6,测试代码

头结点校验空字符串可用:

image.png

尾节点校验可用:

image.png

获取真实存在的数据可用:

image.png

image.png

至此我的想法算是已经完成了,后面还在想,其实返回值可以是个Field,然后在工厂方法中统一处理,上面这些代码只是完成了我的想法的一个初步阶段,如果有人对这块代码感兴趣,可以给出更好的解决方案,欢迎评论区讨论~