Java8中如何不使用instanceof与访问者模式调用适配Box不同实现类的重载方法
解决方案
问题根源:Java的方法重载是静态分派,只会根据编译期变量类型匹配方法,你声明的变量是Box类型,编译期无法匹配到具体实现类的重载方法,所以会报错。
以下方案不需要修改模型层,也不需要使用instanceof或者访问者模式:
方案:使用类型映射表实现动态派发
思路:在视图层的BoxAdapterToRenderer类内部维护一个「Box实现类 -> 对应渲染构造函数」的映射表,运行时根据实例的实际类型匹配对应的构造逻辑,所有逻辑都收敛在视图层,完全不侵入模型层代码。
修改后的完整代码如下:
import java.util.HashMap; import java.util.Map; import java.util.function.Function; public class BoxAdapterToRenderer { // 类型映射表,key为Box实现类的Class对象,value为对应类型的渲染构造函数 private static final Map<Class<? extends Box>, Function<? extends Box, Node>> RENDERER_FACTORY_MAP = new HashMap<>(); // 静态块初始化映射关系 static { RENDERER_FACTORY_MAP.put(Fighter.class, (Function<Fighter, Node>) BoxAdapterToRenderer::createRenderer); RENDERER_FACTORY_MAP.put(Bomb.class, (Function<Bomb, Node>) BoxAdapterToRenderer::createRenderer); RENDERER_FACTORY_MAP.put(Mine.class, (Function<Mine, Node>) BoxAdapterToRenderer::createRenderer); RENDERER_FACTORY_MAP.put(StaminaPad.class, (Function<StaminaPad, Node>) BoxAdapterToRenderer::createRenderer); } // 新增入参为Box的公共调用入口 public static Node createRenderer(Box box) { Function<Box, Node> factory = (Function<Box, Node>) RENDERER_FACTORY_MAP.get(box.getClass()); if (factory == null) { // 可按需处理未知Box类型的兜底逻辑,比如返回默认占位节点 throw new IllegalArgumentException("无对应渲染逻辑的Box类型: " + box.getClass().getName()); } return factory.apply(box); } // 原有各类型的重载方法保持不变 public static Node createRenderer(Fighter fighter){ Rectangle fighterRenderer = new Rectangle(); fighterRenderer.setHeight(50); fighterRenderer.setWidth(50); Image im = new Image(Constants.ruleReader.getFighterImageURL(fighter.getName()),false); fighterRenderer.setFill(new ImagePattern(im)); return fighterRenderer; } public static Node createRenderer(Bomb bomb){ Rectangle bombRenderer = new Rectangle(); bombRenderer.setHeight(50); bombRenderer.setWidth(50); Image im = new Image(Constants.ruleReader.getBombImageURL(),false); bombRenderer.setFill(new ImagePattern(im)); return bombRenderer; } public static Node createRenderer(Mine mine){ Rectangle mineRenderer = new Rectangle(); mineRenderer.setHeight(50); mineRenderer.setWidth(50); Image im = new Image(Constants.ruleReader.getMineImageURL(),false); mineRenderer.setFill(new ImagePattern(im)); return mineRenderer; } public static Node createRenderer(StaminaPad staminaPad){ Rectangle staminaPadRenderer = new Rectangle(); staminaPadRenderer.setHeight(50); staminaPadRenderer.setWidth(50); Image im = new Image(Constants.ruleReader.getStaminaPadImageURL(),false); staminaPadRenderer.setFill(new ImagePattern(im)); return staminaPadRenderer; } }
方案优势
- 完全符合MVC分层约束,所有视图相关逻辑都在视图层,模型层代码无任何修改
- 没有链式
instanceof判断,运行时查找效率为O(1) - 后续新增Box实现类时,只需要新增对应重载方法、在静态块中加一行映射配置即可,符合开闭原则
- 调用方式和你期望的完全一致,无需修改现有调用代码:
Box box = board.getGrid()[i][j]; Node renderer = BoxAdapterToRenderer.createRenderer(box);
内容的提问来源于stack exchange,提问作者Mattéo Da silva
相关产品推荐
相关产品推荐

