【问题标题】:Dynamic dispatch and generic interface factories动态调度和通用接口工厂
【发布时间】:2015-12-19 11:05:46
【问题描述】:

我应该如何在Factory 中实现RequestFactory 接口,以便我可以根据传递的类型创建StringRequestIntRequest

本质上我想动态创建参数抽象类的具体类的实例,这在 Java 中可能吗?

public class Main {

    public static void main(String[] args) {
        Integer mInt = 10;
        String mString = "string";

        MyRequest mReq1 = new Factory<>(mString).getRequest();
        mReq1.PerformMyRequest();

        MyRequest mReq2 = new Factory<>(mInt).getRequest();
        mReq2.PerformMyRequest();
    }
}

class Factory<T> implements RequestFactory<T> {

    private final MyRequest<T> Req;

    public Factory(T body) {
        Req = create(body);
    }

    public MyRequest<T> getRequest() {
        return Req;
    }

    @Override
    // How do I implement the interface here so
    // that correct factory is invoked depending on T
    // so that I can return either StringRequest or IntRequest
    public MyRequest<T> create(T body) {
        return null;
    }

}

工厂接口:

// Interface
interface RequestFactory<T> {
    MyRequest<T> create(T body);
}
// Concrete specialized factories
class StringFactory implements RequestFactory<String> {
    @Override
    public StringRequest create(String body) {
        return new StringRequest(body);
    }
}
class IntFactory implements RequestFactory<Integer> {
    @Override
    public IntRequest create(Integer body) {
        return new IntRequest(body);
    }
}

具有两个具体子级的通用抽象类

// ======================================================

// AbstractClass
abstract class MyRequest<T> {
    T mVal;

    MyRequest(T body) {
        mVal = body;
    }

    public void PerformMyRequest() {
        System.out.println("-> From abstract: " + mVal);

    }

}
// Concrete classes that I'd like to automatically
// create using the factory above
class StringRequest extends MyRequest<String> {

    StringRequest(String body) {
        super(body);
    }

    public void PerformMyRequest() {
        super.PerformMyRequest();
        System.out.println("  -> From StringRequest");
    }
}
class IntRequest extends MyRequest<Integer> {

    IntRequest(Integer body) {
        super(body);
    }

    public void PerformMyRequest() {
        super.PerformMyRequest();
        System.out.println("  -> From IntRequest");
    }
}

【问题讨论】:

    标签: java generics factory dispatch


    【解决方案1】:

    java 无法做到这一点。您可以通过编写“MetaFactory”(即工厂的工厂)来完成此操作,该工厂进行类型检查以选择要创建和返回的工厂实现。

    public final class RequestMetaFactory {
    
      public RequestFactory<T> newFactory(T req) {
        if (req instanceof String) {
          return new StringRequestFactory((String)req);
        }
    
        if (req instanceof Integer) {
          return new IntegerRequestFactory((Integer)req);
        }
    
        throw new IllegalArgumentException(req.getClass() + " not a supported arg type");
      }
    
    }
    

    这可以通过执行 SPI 查找来查找实际的 RequestFactory 实例并询问它们支持的类型来变得更加复杂。

    【讨论】:

      【解决方案2】:

      在 Java 中,泛型类型仅用于编译时类型检查,通常在运行时不可用。这意味着您无法在 create 方法中基于 T 做出任何运行时决策。

      您也不能只是从知道您想要RequestFactory&lt;String&gt; 到知道为此目的的“具体”实现是StringFactory。可能还有其他类也扩展了RequestFactory&lt;String&gt;,因此您必须在某处明确声明StringFactory 是您想要的。如果这是 C++,您可以编写模板特化来说明“这是RequestFactory&lt;String&gt; 实现”,但对于泛型,这是不可能的。

      Brett Okken 已经指出了一种可能的替代解决方案,该解决方案与我所写的非常相似,所以我只指出他的答案。

      【讨论】:

      • 有 C++ 背景的我痴迷于这样做 2 天,应该早点问:) 谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-22
      相关资源
      最近更新 更多