如何优化Action与Technique实体建模以避免类型转换问题
优化Action与Technique的类型安全设计方案
问题背景
你的代码里有这么一套结构:
- 基类
Action,子类包含SimpleAction1、SimpleAction2和BaseComplexAction;BaseComplexAction又衍生出ComplexAction1、ComplexAction2 - 泛型接口
Technique<T extends Action>,提供两个方法:T getActions()生成对应类型的Action,boolean matchesAction(T action)判断Action是否由当前Technique生成
现在遇到两个麻烦:
- 调用
matchesAction时,必须把泛型Action转成Technique支持的具体类型,容易出类型转换错误 - 如果把Technique的泛型去掉,每个实现类又得先手动检查Action类型再转换,代码冗余又麻烦
下面给几个实用的优化方案,不用再跟类型转换较劲:
方案1:给Technique加默认方法,自动处理类型检查
这个方案改动最小,保留原有泛型结构,新增一个默认方法帮你做类型校验和转换:
interface Technique<T extends Action> { T getActions(); boolean matchesAction(T action); // 新增:让实现类返回自己支持的Action类型 Class<T> getSupportedActionType(); // 默认方法,对外暴露无需类型转换的匹配逻辑 default boolean matches(Action action) { if (getSupportedActionType().isInstance(action)) { // 内部自动转换类型,外部调用不用管 return matchesAction(getSupportedActionType().cast(action)); } return false; } }
具体实现类只需要多实现一个返回类型的方法:
class MyTechnique implements Technique<BaseComplexAction> { @Override public BaseComplexAction getActions() { return new ComplexAction1(); } @Override public boolean matchesAction(BaseComplexAction action) { return action instanceof ComplexAction1; } @Override public Class<BaseComplexAction> getSupportedActionType() { return BaseComplexAction.class; } }
调用的时候直接传任意Action实例就行,完全不用手动转换:
Action action = new ComplexAction1(); Technique<?> technique = new MyTechnique(); // 直接调用matches,内部自动处理类型 boolean isMatch = technique.matches(action);
方案2:用访客模式彻底消除类型转换
如果你的Action类型多,而且匹配逻辑复杂,访客模式是个更优雅的选择,让Action主动适配Technique的检查:
首先给Action基类加一个accept方法:
abstract class Action { public abstract boolean accept(TechniqueVisitor visitor); } // 定义访客接口,每个Action类型对应一个visit方法 interface TechniqueVisitor { boolean visit(SimpleAction1 action); boolean visit(SimpleAction2 action); boolean visit(ComplexAction1 action); boolean visit(ComplexAction2 action); }
然后每个Action子类实现accept方法,把自己传给访客:
class SimpleAction1 extends Action { @Override public boolean accept(TechniqueVisitor visitor) { return visitor.visit(this); } } class ComplexAction1 extends BaseComplexAction { @Override public boolean accept(TechniqueVisitor visitor) { return visitor.visit(this); } } // 其他Action子类照猫画虎实现accept就行
接下来调整Technique接口,让实现类同时实现TechniqueVisitor:
interface Technique { Action getActions(); boolean matchesAction(Action action); } class MyTechnique implements Technique, TechniqueVisitor { @Override public Action getActions() { return new ComplexAction1(); } @Override public boolean matchesAction(Action action) { // 直接让Action自己处理匹配逻辑 return action.accept(this); } @Override public boolean visit(SimpleAction1 action) { return false; // 不匹配SimpleAction1 } @Override public boolean visit(SimpleAction2 action) { return false; } @Override public boolean visit(ComplexAction1 action) { return true; // 匹配ComplexAction1 } @Override public boolean visit(ComplexAction2 action) { return false; } }
调用的时候直接传Action,完全不用考虑类型问题,所有类型匹配逻辑都在visit方法里,清晰又安全。
方案3:基于类型令牌的泛型严格约束
如果你想保留泛型的类型安全,同时简化外部调用,这个方案刚好合适:
interface Technique<T extends Action> { T getActions(); boolean matchesAction(T action); // 返回当前Technique支持的Action类型令牌 Class<T> getActionType(); // 对外的无参匹配方法,内部自动处理类型 default boolean matches(Action action) { return getActionType().isInstance(action) && matchesAction(getActionType().cast(action)); } } // 实现类示例 class Complex1Technique implements Technique<ComplexAction1> { @Override public ComplexAction1 getActions() { return new ComplexAction1(); } @Override public boolean matchesAction(ComplexAction1 action) { // 这里可以加更细致的匹配逻辑,比如检查Action的属性 return true; } @Override public Class<ComplexAction1> getActionType() { return ComplexAction1.class; } }
调用示例:
Action action = new ComplexAction1(); Technique<?> tech = new Complex1Technique(); boolean matches = tech.matches(action); // 无需任何类型转换
方案选择建议
- 要是你不想大改原有代码,只是想解决类型转换问题,方案1最省事
- 要是你的Action类型多,匹配逻辑复杂,以后还可能加新的Action,方案2扩展性最好
- 要是你想严格保留泛型的类型约束,同时简化调用,方案3最合适
内容的提问来源于stack exchange,提问作者Adriano Todaro
相关产品推荐
相关产品推荐

