You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java如何优雅从HashMap获取指定类型规则对象优化调用写法

问题根因

你当前需要强制类型转换、静态方法耦合的核心原因是Rule接口没有定义统一的实例方法契约,所有规则的执行逻辑都写成了静态方法,接口完全没起到抽象层的作用。

优化方案

1. 重构Rule接口,定义统一行为契约

把所有规则共有的执行方法定义为接口的实例方法签名,删掉所有实现类里resolveRule的static修饰符,让实现类重写接口方法:

public interface Rule {
    // 通用规则执行方法,入参与你现有逻辑保持一致
    void resolveRule(Tile tilePosee, FrameTT frame, Board board);

    // 针对部分规则需要多参数的场景,加默认重载方法,避免强转
    default void resolveRule(Tile self, Tile target, Direction dir, FrameTT frame, Board board) {
        throw new UnsupportedOperationException("当前规则不支持邻接格子结算逻辑");
    }

    // 注入规则容器的默认方法,不需要依赖其他规则的实现类不用重写
    default void setRuleRegistry(Map<RuleType, Rule> registry) {}
}

改完之后从Map里取出的Rule实例可以直接调用resolveRule,完全不需要强制类型转换,你之前的强转代码可以直接删掉:

// 废弃原有强转写法
callRule(ruleList, COMBO).resolveRule(tileDirection, frame, board);

2. 解决规则间互相调用的耦合问题

你之前用静态方法主要是为了跨规则调用,这里不要写死类名做静态调用,两种低改动的实现方式可选:

方式A:注入规则注册表(耦合度最低)

初始化规则Map时,把容器引用注入到每个规则实例中,规则内部直接通过容器拿依赖的其他规则即可,不需要静态耦合:

// 初始化规则Map时建议用EnumMap,枚举作为键时性能比HashMap更好
private Map<RuleType, Rule> ruleList = new EnumMap<>(RuleType.class);

private void createRuleMap() {
    // 先注册所有规则实例,规则本身无状态,全局初始化一次即可
    ruleList.put(COMBO, new RuleCombo());
    ruleList.put(ELEMENTALE, new RuleElementales());
    ruleList.put(IDENTIQUE, new RuleIdentique());
    ruleList.put(MEMEMUR, new RuleMemeMur());
    ruleList.put(PLUS, new RulePlus());
    // 统一注入规则容器
    ruleList.values().forEach(rule -> rule.setRuleRegistry(ruleList));
}

以RuleCombo为例,改造后的代码如下:

public class RuleCombo implements Rule {
    private Map<RuleType, Rule> ruleRegistry;

    @Override
    public void setRuleRegistry(Map<RuleType, Rule> registry) {
        this.ruleRegistry = registry;
    }

    @Override
    public void resolveRule(Tile tilePosee, FrameTT frame, Board board) {
        if (ruleExisting(IDENTIQUE)) {
            ruleRegistry.get(IDENTIQUE).resolveRule(tilePosee, frame, board);
        }
        if (ruleExisting(PLUS)) {
            ruleRegistry.get(PLUS).resolveRule(tilePosee, frame, board);
        }
        for (Direction direction : Direction.values()) {
            Tile tileDirection = getAdjacentTile(tilePosee, direction, board);
            if (checkTileExist(tileDirection)) {
                if ((tileDirection.getPlayer() != tilePosee.getPlayer()) && checkTileIsOccupied(tileDirection)) {
                    if (ruleExisting(ELEMENTALE)) {
                        // 直接调用接口重载的多参数方法,不需要强转
                        ruleRegistry.get(ELEMENTALE).resolveRule(tilePosee, tileDirection, direction, frame, board);
                    } else {
                        cardPoseeWin(tilePosee, tileDirection, direction, frame, board);
                    }
                }
            }
        }
    }
}

方式B:全局规则上下文(现有代码改动最小)

如果不想给每个规则加注入逻辑,可以把规则容器封装成全局上下文,提供静态访问方法,规则直接从上下文取依赖即可:

public class RuleContext {
    private static final Map<RuleType, Rule> RULE_MAP = new EnumMap<>(RuleType.class);

    // 游戏初始化时调用一次
    public static void init() {
        RULE_MAP.put(COMBO, new RuleCombo());
        RULE_MAP.put(ELEMENTALE, new RuleElementales());
        RULE_MAP.put(IDENTIQUE, new RuleIdentique());
        RULE_MAP.put(MEMEMUR, new RuleMemeMur());
        RULE_MAP.put(PLUS, new RulePlus());
    }

    public static Rule getRule(RuleType type) {
        Rule rule = RULE_MAP.get(type);
        if (rule == null) throw new IllegalArgumentException("未注册的规则类型:" + type);
        return rule;
    }

    public static boolean hasRule(RuleType type) {
        return RULE_MAP.containsKey(type);
    }
}

这种方式下,你原有代码里的ruleExisting判断直接替换成RuleContext.hasRule(xxx),调用其他规则直接写RuleContext.getRule(xxx).resolveRule(...)即可,改动量极小。

额外优化建议

  • 你当前封装的callRule静态方法没有额外价值,直接从Map/上下文获取规则即可,不需要多包一层
  • 把checkTileExist、getAdjacentTile、cardPoseeWin这类所有规则共用的工具逻辑抽到单独的RuleUtils或BoardUtils类中,不要散落在各个规则类里重复实现
  • 所有规则实例都是无状态的,全局只初始化一次即可,不需要每次执行规则时创建新实例

内容的提问来源于stack exchange,提问作者Simon Debelmas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 06:33:59