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

如何重写Java代码避免switch分支与强制类型转换,适配Quarkus CDI场景

解决方案

方案1:访问者模式(零类型转换,无需依赖框架特性)

该方案为纯面向对象设计实现,不依赖CDI能力,所有Service可保持无状态单例:
首先定义访问者接口:

interface ConfigVisitor {
    String visit(ConfigA configA);
    String visit(ConfigB configB);
}

修改Config基类和子类:

abstract class Config {
    public abstract String accept(ConfigVisitor visitor);
}

class ConfigA extends Config {
    @Override
    public String accept(ConfigVisitor visitor) {
        return visitor.visit(this);
    }
}

class ConfigB extends Config {
    @Override
    public String accept(ConfigVisitor visitor) {
        return visitor.visit(this);
    }
}

让业务Service实现Visitor接口,保持无状态:

@ApplicationScoped
class ServiceA implements ConfigVisitor {
    @Override
    public String visit(ConfigA configA) {
        // 原ServiceA的业务逻辑,直接使用configA无需转换
        return ...;
    }

    @Override
    public String visit(ConfigB configB) {
        throw new UnsupportedOperationException();
    }
}

// 同理实现ServiceB
@ApplicationScoped
class ServiceB implements ConfigVisitor {
    @Override
    public String visit(ConfigA configA) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String visit(ConfigB configB) {
        // 原ServiceB的业务逻辑
        return ...;
    }
}

最后实现ServiceRunner:

@ApplicationScoped
class ServiceRunner {
    private final Map<Class<? extends Config>, ConfigVisitor> serviceMap;

    // Quarkus CDI支持构造器注入所有匹配类型的bean,提前绑定Config类型和对应Service
    public ServiceRunner(Instance<ConfigVisitor> visitors) {
        Map<Class<? extends Config>, ConfigVisitor> map = new HashMap<>();
        map.put(ConfigA.class, visitors.select(ServiceA.class).get());
        map.put(ConfigB.class, visitors.select(ServiceB.class).get());
        this.serviceMap = Collections.unmodifiableMap(map);
    }

    public String run(Config config) {
        // 完全不需要类型转换和instanceof判断
        return config.accept(serviceMap.get(config.getClass()));
    }
}

方案2:CDI自动注册策略(无需修改现有Config类)

如果不想改动原有Config的继承结构,可利用Quarkus CDI的能力自动注册策略,仅在框架内部封装类型转换,对外完全无感知:
首先定义通用Service接口:

interface ConfigService<T extends Config> {
    String run(T config);
    Class<T> getSupportedConfigType();
}

实现对应的业务Service:

@ApplicationScoped
class ServiceA implements ConfigService<ConfigA> {
    @Override
    public String run(ConfigA configA) {
        // 业务逻辑
        return ...;
    }

    @Override
    public Class<ConfigA> getSupportedConfigType() {
        return ConfigA.class;
    }
}

@ApplicationScoped
class ServiceB implements ConfigService<ConfigB> {
    @Override
    public String run(ConfigB configB) {
        // 业务逻辑
        return ...;
    }

    @Override
    public Class<ConfigB> getSupportedConfigType() {
        return ConfigB.class;
    }
}

实现ServiceRunner:

@ApplicationScoped
class ServiceRunner {
    private final Map<Class<? extends Config>, ConfigService<?>> serviceMap;

    public ServiceRunner(Instance<ConfigService<?>> services) {
        Map<Class<? extends Config>, ConfigService<?>> map = new HashMap<>();
        for (ConfigService<?> service : services) {
            map.put(service.getSupportedConfigType(), service);
        }
        this.serviceMap = Collections.unmodifiableMap(map);
    }

    @SuppressWarnings("unchecked")
    public String run(Config config) {
        // 此处强转已通过预绑定保证类型安全,对外调用完全无感知
        ConfigService<Config> service = (ConfigService<Config>) serviceMap.get(config.getClass());
        return service.run(config);
    }
}

两种方案都完全避免了业务代码中的instanceof判断和硬编码分支,新增Config类型时仅需要新增对应Service实现即可,无需修改ServiceRunner代码,符合开闭原则,且所有Service都为无状态单例,适配Quarkus CDI的运行模型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 10:15:02