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

如何使用Java8 Supplier接口重写工厂方法以提供正确类型实例?

使用Java 8 Supplier重构Thingy工厂方法

嘿,这个问题我刚好琢磨过,咱们一步步把它搞定!原来的工厂用反射创建实例不仅有运行时风险,还得加一堆unchecked警告,换成Supplier之后不仅代码更清爽,类型安全也更有保障。

第一步:调整工厂的存储结构

原来你用Map<String, Class<Thingy<?, ?>>>来存实现类,现在咱们把它换成存Supplier实例——毕竟Supplier的核心就是提供实例,完全贴合工厂的需求:

public final class ThingyFactory {
    // 替换原来的thingyclasses,用Supplier存储实例提供者
    private final Map<String, Supplier<? extends Thingy<?, ?>>> thingySuppliers = new ConcurrentHashMap<>();
    // ... 其他代码
}

第二步:实现注册方法

现在注册Thingy实现类的时候,不用传Class对象了,直接传一个Supplier。你可以用方法引用(比如ConcreteThingy::new)来快速创建Supplier,非常方便:

// 泛型化的注册方法,保证类型一致性
public <K, V> void registerThingy(String key, Supplier<Thingy<K, V>> supplier) {
    thingySuppliers.put(key, supplier);
}

举个注册的例子,假设你有个ConcreteThingy实现了Thingy<String, Integer>:

factory.registerThingy("string-int", ConcreteThingy::new);

第三步:重构获取实例的方法

原来的反射创建逻辑可以直接替换成调用Supplier的get()方法,虽然还是需要一个unchecked警告,但相比反射的场景,这个警告的风险要小得多——毕竟注册时已经绑定了正确的构造逻辑:

@SuppressWarnings("unchecked") // 仅在必要时保留,比反射更安全
public <K, V> Thingy<K, V> getThingy(String key) {
    Supplier<? extends Thingy<?, ?>> supplier = thingySuppliers.get(key);
    if (supplier == null) {
        throw new IllegalArgumentException("找不到对应key的Thingy实现:" + key);
    }
    // 这里的类型转换是安全的,因为注册时我们已经确保Supplier返回对应类型
    return (Thingy<K, V>) supplier.get();
}

完整示例代码

咱们把所有部分拼起来,看看实际运行效果:

Thingy接口

public interface Thingy<K, V> extends Map<K, V> {}

具体实现类

public class ConcreteThingy<K, V> implements Thingy<K, V> {
    // 用HashMap做委托,简化Map方法的实现
    private final Map<K, V> delegate = new HashMap<>();

    @Override
    public int size() { return delegate.size(); }
    @Override
    public boolean isEmpty() { return delegate.isEmpty(); }
    @Override
    public boolean containsKey(Object key) { return delegate.containsKey(key); }
    @Override
    public boolean containsValue(Object value) { return delegate.containsValue(value); }
    @Override
    public V get(Object key) { return delegate.get(key); }
    @Override
    public V put(K key, V value) { return delegate.put(key, value); }
    @Override
    public V remove(Object key) { return delegate.remove(key); }
    @Override
    public void putAll(Map<? extends K, ? extends V> m) { delegate.putAll(m); }
    @Override
    public void clear() { delegate.clear(); }
    @Override
    public Set<K> keySet() { return delegate.keySet(); }
    @Override
    public Collection<V> values() { return delegate.values(); }
    @Override
    public Set<Entry<K, V>> entrySet() { return delegate.entrySet(); }
}

重构后的ThingyFactory

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public final class ThingyFactory {
    private final Map<String, Supplier<? extends Thingy<?, ?>>> thingySuppliers = new ConcurrentHashMap<>();

    public <K, V> void registerThingy(String key, Supplier<Thingy<K, V>> supplier) {
        thingySuppliers.put(key, supplier);
    }

    @SuppressWarnings("unchecked")
    public <K, V> Thingy<K, V> getThingy(String key) {
        Supplier<? extends Thingy<?, ?>> supplier = thingySuppliers.get(key);
        if (supplier == null) {
            throw new IllegalArgumentException("No Thingy registered for key: " + key);
        }
        return (Thingy<K, V>) supplier.get();
    }

    // 测试代码
    public static void main(String[] args) {
        ThingyFactory factory = new ThingyFactory();
        factory.registerThingy("string-int", ConcreteThingy::new);

        Thingy<String, Integer> myThingy = factory.getThingy("string-int");
        myThingy.put("answer", 42);
        System.out.println("The answer is: " + myThingy.get("answer")); // 输出42
    }
}

为什么这么做更好?

  • 避免反射风险:不用再处理InstantiationException、IllegalAccessException这些运行时异常,注册时如果构造方法有问题,编译阶段就会报错。
  • 代码更简洁:方法引用ConcreteThingy::new比反射代码可读性高太多。
  • 类型更安全:注册时就绑定了正确的泛型类型,相比反射的强制转换,风险大幅降低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:16:35