表驱动法, 实战中学会和 if...else 及 switch 之间进行取舍

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/u010979642/article/details/102746939

1. 概念

表驱动法就是一种编程模式,从表里面查找信息而不使用逻辑语句。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。 - 引用自《代码大全》

所谓表驱动法(Table-Driven Approach), 又称之为表驱动、表驱动方法。 简单讲是指用查表的方式获取值。

2. 常用查表方式

  • 直接访问(直接访问表).
  • 索引访问(索引访问表)
  • 分段访问(阶梯访问表)

3. 实战PK

场景描述: 根据压缩包的后缀名来判断具体调用哪个方法来进行解压

3.1 解压工具类

public class AIUtil {
    private AIUtil() {}
	
    // 解压 zip 包
    public static List<String> unzip(String srcPath) {
        System.out.println(format("进入 unzip 方法. srcPath={0}.", srcPath));
        // 具体解压过程省略...
        return Lists.newArrayList(srcPath + File.separator + "/desc");
    }

    // 解压 tar 包
    public static List<String> untar(String srcPath, int limit) {
        System.out.println(format("进入 untar 方法. srcPath={0}, limit={1}.", srcPath, limit));
        // 具体解压过程省略...
        return Lists.newArrayList(srcPath + File.separator + "/desc");
    }

    // 解压 rar 包
    public static List<String> unrar(String srcPath, boolean force) {
        System.out.println(format("进入 unrar 方法. srcPath={0}, force={1}.", srcPath, force));
        // 具体解压过程省略...
        return Lists.newArrayList(srcPath + File.separator + "/desc");
    }

	// 其他压缩包格式解压函数方法...
}

3.2 常规条件判断实现方式

使用常规的 if…else 条件语句进行逻辑判断

3.2.1 核心工厂方法

private static void logicJudge(String suffix, String srcPath, int limit, boolean force) {
    List<String> images = null;
    if (".zip".equals(suffix)) {
        images = AIUtil.unzip(srcPath);
    } else if (".tar".equals(suffix)) {
        images = AIUtil.untar(srcPath, limit);
    } else if (".rar".equals(suffix)) {
        images = AIUtil.unrar(srcPath, force);
    }
    // 需求迭代, 现在需要支持其他格式的压缩包解压, 则此处需要新增 if...else 逻辑
    
    System.out.println(MessageFormat.format("方法 {0} 返回值为={1}", suffix, images));
}

3.2.2 测试用例

logicJudge(".zip", "/data/zip", -1, true);
System.out.println();

logicJudge(".tar", "/data/tar", 10, true);
System.out.println();

logicJudge(".rar", "/data/rar", -1, false);
System.out.println();

3.2.3 运行结果

进入 unzip 方法. srcPath=/data/zip.
方法 .zip 返回值为=[/data/zip\/desc]

进入 untar 方法. srcPath=/data/tar, limit=10.
方法 .tar 返回值为=[/data/tar\/desc]

进入 unrar 方法. srcPath=/data/rar, force=false.
方法 .rar 返回值为=[/data/rar\/desc]

3.3 枚举访问表方式

3.3.1 核心方法

@SuppressWarnings("unchecked")
private static void tableDrive(String suffix, List<Object> params) throws Exception {
    MethodEnum method = MethodEnum.suffix2Method(suffix);
    List<String> images = (List<String>) AIUtil.class.getMethod(method.methodName(), method.parameterTypes()).invoke(null, params.toArray());
    System.out.println(format("方法 {0} 返回值为={1}", method.methodName(), images));
}

3.3.2 核心枚举类表

public enum MethodEnum {
    /** zip 包 */
    UNZIP(".zip", "unzip", String.class),
    /** tar 包 */
    UNTAR(".tar", "untar", String.class, int.class),
    /** rar 包 */
    UNRAR(".rar", "unrar", String.class, boolean.class)
	
	// 如果需要支持其他格式的压缩包解压, 只需要在此处添加对应的枚举元素即可
	;

    // 文件后缀名
    private String suffixName;
    // 执行的解压方法名
    @Getter
    private String methodName;
    // 执行方法的参数
    @Getter
    private Class[] parameterTypes;

    MethodEnum(String suffixName, String methodName, Class... parameterTypes) {
        this.suffixName = suffixName;
        this.methodName = methodName;
        this.parameterTypes = parameterTypes;
    }

    public static MethodEnum suffix2Method(String suffixName) {
        for (MethodEnum method : MethodEnum.values()) {
            if (method.suffixName.equals(suffixName)) {
                return method;
            }
        }
        throw new IllegalArgumentException(suffixName);
    }
}

特别说明: parameterTypes 填写顺序需要和具体解压方法的入参保持一致

3.3.3 测试用例

tableDrive(".zip", Lists.newArrayList("/data/zip"));
System.out.println();

tableDrive(".tar", Lists.newArrayList("/data/tar", 10));
System.out.println();

tableDrive(".rar", Lists.newArrayList("/data/rar", false));
System.out.println();

3.3.4 运行结果

进入 unzip 方法. srcPath=/data/zip.
方法 unzip 返回值为=[/data/zip\/desc]

进入 untar 方法. srcPath=/data/tar, limit=10.
方法 untar 返回值为=[/data/tar\/desc]

进入 unrar 方法. srcPath=/data/rar, force=false.
方法 unrar 返回值为=[/data/rar\/desc]

3.4 枚举访问表方式(优化版)

3.4.1 核心方法

private static void tableDrive(String suffix, List<Object> params) throws Exception {
	List<String> images = (List<String>) METHODS_MAP.get(suffix).exeMethod().invoke(null, params.toArray());
    System.out.println(format("方法 {0} 返回值为={1}", suffix, images));
}

3.4.2 方法接口类

反射生成具体的解压执行方法

public interface IMethod {
    // 反射生成解压具体执行方法
    Method exeMethod() throws Exception;
}

3.4.3 核心枚举类表

public enum MethodEnum implements IMethod {
    /** zip 包 */
    UNZIP(".zip") {
        @Override
        public Method exeMethod() throws Exception {
            return UNZIP_TOOP_CLASS.getMethod("unzip", String.class);
        }
    },
    /** tar 包 */
    UNTAR(".tar") {
        @Override
        public Method exeMethod() throws Exception {
            return UNZIP_TOOP_CLASS.getMethod("untar", String.class, int.class);
        }
    },
    /** rar 包 */
    UNRAR(".rar") {
        @Override
        public Method exeMethod() throws Exception {
            return UNZIP_TOOP_CLASS.getMethod("unrar", String.class, boolean.class);
        }
    }
    ;

    // 压缩包解压工具类类名
    private static final Class<?> UNZIP_TOOP_CLASS = AIUtil.class;
    // 具体解压方法名和对应枚举映射集
    public static final Map<String, IMethod> METHODS_MAP = Maps.newHashMap();
    static {
        for (MethodEnum method : MethodEnum.values()) {
            METHODS_MAP.put(method.suffixName, method);
        }
    }

    // 文件后缀名
    private String suffixName;

    MethodEnum(String suffixName) {
        this.suffixName = suffixName;
    }
}

3.5 枚举访问表方式(升级版)

3.5.1 核心方法

private static void tableDrive(String suffix, List<Object> params) throws Exception {
	List<String> images = (List<String>) METHODS_MAP.get(suffix).exeMethod().invoke(null, params.toArray());
    System.out.println(format("方法 {0} 返回值为={1}", suffix, images));
}

3.5.2 方法接口类

反射生成具体的解压执行方法

public interface IMethod {
    // 反射生成解压具体执行方法
    Method exeMethod() throws Exception;
}

3.5.3 核心枚举类表

public enum MethodEnum implements IMethod {
    /** zip 包 */
    UNZIP(".zip") {
        @Override
        public Method exeMethod() throws Exception {
            return UNZIP_METHOD;
        }
    },
    /** tar 包 */
    UNTAR(".tar") {
        @Override
        public Method exeMethod() throws Exception {
            return UNTAR_METHOD;
        }
    },
    /** rar 包 */
    UNRAR(".rar") {
        @Override
        public Method exeMethod() throws Exception {
            return UNRAR_METHOD;
        }
    }
    ;

    // 具体解压方法名和对应枚举映射集
    public static final Map<String, IMethod> METHODS_MAP = Maps.newHashMap();
    private static Method UNZIP_METHOD, UNTAR_METHOD, UNRAR_METHOD;
    static {
        // 压缩包解压工具类类名
        final Class<?> unzipToolClz = AIUtil.class;
        try {
            // 把耗时的反射代码挪到类初始化的时候执行
            UNZIP_METHOD = unzipToolClz.getMethod("unzip", String.class);
            UNTAR_METHOD = unzipToolClz.getMethod("untar", String.class, int.class);
            UNRAR_METHOD = unzipToolClz.getMethod("unrar", String.class, boolean.class);
            // 若要支持其他格式的压缩包, 此处也需反射获取对应的解压方法

            for (MethodEnum method : MethodEnum.values()) {
                METHODS_MAP.put(method.suffixName, method);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    // 文件后缀名
    private String suffixName;

    MethodEnum(String suffixName) {
        this.suffixName = suffixName;
    }
}

3.6 哈希索引访问表方式(最终版)-推荐

3.6.1 核心哈希索引表

// 具体解压方法名和对应枚举映射集
public static final Map<String, Method> METHODS_MAP = Maps.newHashMap();
static {
    // 压缩包解压工具类类名
    final Class<?> unzipToolClz = AIUtil.class;
    try {
        // 把耗时的反射代码挪到类初始化的时候执行
        METHODS_MAP.put(".zip", unzipToolClz.getMethod("unzip", String.class));
        METHODS_MAP.put(".tar", unzipToolClz.getMethod("untar", String.class, int.class));
        METHODS_MAP.put(".rar", unzipToolClz.getMethod("unrar", String.class, boolean.class));
        // 若要支持其他格式的压缩包, 此处也需反射获取对应的解压方法
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

3.6.2 核心方法

private static void tableDrive(String suffix, List<Object> params) throws Exception {
 	List<String> images = (List<String>) METHODS_MAP.get(suffix).invoke(null, params.toArray());
    System.out.println(format("方法 {0} 返回值为={1}", suffix, images));
}

猜你喜欢

转载自blog.csdn.net/u010979642/article/details/102746939