简体   繁体   English

简单工厂使用generics如何解决这个困境

[英]How to resolve this dilemma when using generics in a simple factory

I have a Data class with several sub-class such as JSONData , XMLData , IntegerData .我有一个Data class 和几个子类,例如JSONDataXMLDataIntegerData The task is to process different types of incoming data.任务是处理不同类型的传入数据。 So based on program to an interface, not an implementation , I created the following interface with generic type for compile-time type checking:因此,基于对接口的程序,而不是实现,我创建了以下具有泛型类型接口,用于编译时类型检查:

interface DataProcessor<T extends Data> {
    void process(T data);
}

There are several implemenations based on this interface:基于这个接口有几个实现:

* `class JSONDataProcessor implements DataProcessor<JSONData>`
* `class XMLDataProcessor implements DataProcessor<XMLData>`
* `class IntegerDataProcessor implements DataProcessor<IntegerData>`

The rest of the work is to make a simple factory for creating the corresponding DataProcessor instance. rest的工作是制作一个简单的工厂,用于创建相应的DataProcessor实例。 So I made the following simple factory, or say it is in fact just a processor mapper as the concrete processor can be cached as static variables inside the ProcessorFactory:所以我做了以下简单的工厂,或者说它实际上只是一个处理器映射器,因为具体的处理器可以缓存为 ProcessorFactory 中的static 变量

public class ProcessorFactory {
    public static DataProcessor<?> create() {
          //logic of return an instance
    }
}

The design above has a problem - the process method on the returned instance of DataProcessor cannot be called directly:上面的设计有个问题——不能直接调用返回的DataProcessor实例上的process方法:

Data data = jsonData;
ProcessorFactory.create().process(data);

Question: the code above has a compilation error due to the compile-time typing checking as the data has to be the concrete sub-class of Data , how to resolve this?问题:由于数据必须是Data的具体子类,因此由于编译时类型检查,上面的代码有编译错误,如何解决这个问题? Or is the design per se.或者是设计本身。 bad?坏的? if so what would be a better design?如果是这样,什么是更好的设计?

While design patterns are cool and all, the compilation error you reported in your question, was not caused by the lack of double dispatch.虽然设计模式很酷,但您在问题中报告的编译错误并不是由于缺少双重调度造成的。

You get the compilation error because by declaring, for example, this: JSONDataProcessor implements DataProcessor<JSONData>{...} you've declared this method: void process(JSONData data) .您会收到编译错误,例如,通过声明: JSONDataProcessor implements DataProcessor<JSONData>{...}您已声明此方法: void process(JSONData data)

You are probably assuming that <T extends Data> means you can pass an object instance with the static type Data into void process(JSONData data) because, after all, Data extends Data .您可能假设<T extends Data>意味着您可以将具有 static 类型Data的 object 实例传递到void process(JSONData data)中,因为毕竟Data extends Data Except that's not how Java works.除了 Java 的工作方式之外。

One way to look at the cause of your compilation error is to consider a method declaration like: public static void main(String arg){...} .查看编译错误原因的一种方法是考虑如下方法声明: public static void main(String arg){...} Even though String extends Object , it is illegal to pass a reference with static type Object into a method declared as main(String) .即使String extends Object ,将Object类型的引用传递给声明为main(String)的方法也是非法的。

You would get the same compilation error you got with your DataProcessor if you tried to call that method as main(new Object()) .如果您尝试将该方法称为main(new Object()) ,您将得到与DataProcessor相同的编译错误。 It would be overkill to correct a mistake that you made, by introducing an unnecessary design pattern.通过引入不必要的设计模式来纠正所犯的错误将是矫枉过正。 In both your case and in the case of main(String) , the simplest correction is to pass in the type that the method is declared to take.在您的情况和main(String)的情况下,最简单的更正是传递声明方法采用的类型。

…how to resolve this?… ……怎么解决?……

The simplest solution, in my opinion, is to use your methods the way you declared them originally.在我看来,最简单的解决方案是按照您最初声明它们的方式使用您的方法。 If yours is implemented in a similar way that mine is , then I've confirmed that this works…如果您的实施方式与我的类似,那么我已经确认这可行……

...
JSONData data = new JSONData( ... );
ProcessorFactory.create().process(data);
...

This also works in my demo ( no design patterns required )…这也适用于我的演示不需要设计模式)......

DataProcessor< Data< ? > > dProc = DataProcessor.Factory.create( );
Data<String> data = new JSONData( ... );
dProc.process( data );

…is the design per se. ...就是设计本身。 bad?…不好?……

To call a design „ good “ or „ bad “ is subjective.将设计称为“”或“”是主观的。 It's more objective to ask yourself: Is the design correct ?更客观地问自己:设计是否正确 Does it correctly do what you intend it to do?它是否正确地完成了您打算做的事情? If it does what you intend it to do, then it's correct.如果它按照您的意图去做,那么它是正确的。 If it doesn't, then back to the white drawing board.如果没有,那么回到 白色 绘图板。

Another design option you have is to decide not to use Generics at all — nor design patterns .您拥有的另一个设计选项是决定根本不使用 Generics —也不使用设计模式 Something way simpler might be all you need.更简单的方法可能就是您所需要的。

You mentioned: „ program to an interface “.您提到:“程序到接口”。 Maybe all your design needs is plain old subtype polymorphism in the form of old-fashioned interfaces.也许您的所有设计需求都是老式接口形式的普通旧子类型多态性。 Generics might not be the best design choice for what you want to do. Generics 可能不是您想做的最佳设计选择。

This is the classic problem with Java as it doesn't support double dispatching.这是 Java 的经典问题,因为它不支持双重调度。 People have circumvented the problem using visitor pattern.人们已经使用访问者模式规避了这个问题。 In your case, you can possibly expose a visit function inside the Data class that accepts the DataProcessor and run the process method of it.在您的情况下,您可以在接受 DataProcessor 的Data class 中公开访问DataProcessor并运行它的process方法。 Essentially, reverse the things.从本质上讲,扭转局面。

Something like this像这样的东西

interface Data {

  ....
   void visit(DataProcessor processor);
}

Data d = JsonData;
d.visit(jsonDataProcessor processor);

And the visit function for JsonData looks like而对 JsonData 的visit function 看起来像

void visit(JsonDataProcessor processor) {

    processor.process(this);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM