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));
}