1

我需要帮助来生成和实现访问者模式。我们正在使用大量,instanceof这很痛苦。我确信它可以修改,但我不知道该怎么做。

基本上我们有一个接口ProcessData

public interface ProcessData {
  public setDelegate(Object delegate);
  public Object getDelegate();
  //I am sure these delegate methods can use generics somehow
}

现在我们有一个ProcessDataGeneric实现的类ProcessData

public class ProcessDataGeneric implements ProcessData {
  private Object delegate;

  public ProcessDataGeneric(Object delegate) {
    this.delegate = delegate;
  }
}

现在是一个检索 ProcessData 的新接口

interface ProcessDataWrapper {
  public ProcessData unwrap();
}

现在是一个实现包装器的通用抽象类,因此可以检索 ProcessData

@XmlSeeAlso( { ProcessDataMotorferdsel.class,ProcessDataTilskudd.class })
public abstract class ProcessDataCommon implements ProcessDataWrapper {
  protected ProcessData unwrapped;

  public ProcessData unwrap() {
    return unwrapped;
  }
}

现在实施

public class ProcessDataMotorferdsel extends ProcessDataCommon {

  public ProcessDataMotorferdsel() {
    unwrapped = new ProcessDataGeneric(this);
  }
}

相似地

public class ProcessDataTilskudd extends ProcessDataCommon {

  public ProcessDataTilskudd() {
    unwrapped = new ProcessDataGeneric(this);
  }
}

现在当我使用这些类时,我总是需要做instanceof

ProcessDataCommon pdc = null;
if(processData.getDelegate() instanceof ProcessDataMotorferdsel) {
   pdc = (ProcessDataMotorferdsel) processData.getDelegate();
} else if(processData.getDelegate() instanceof ProcessDataTilskudd) {
   pdc = (ProcessDataTilskudd) processData.getDelegate();
}

我知道有更好的方法可以做到这一点,但我不知道如何利用泛型和访问者模式。任何帮助是极大的赞赏。

更新

我想补充一点,这些类只是一个更大的实现的片段。ProcessDataandProcessDataGeneric是代表之外的东西(等等ProcessDataMotorferdsel)。代表们都在扩展ProcessDataCommon

我同意重构可能是最好的做法,但这是已有 2 年历史的生产代码,重构成本很高(时间、测试等)。不过,我愿意这样做。

更新#2

我试图启动通用进程,但是出现编译错误。这就是它现在的样子。

public interface ProcessData<T extends ProcessDataCommon> {
  T getDelegate();
  setDelegate(T delegate);
}

public class ProcessDataGeneric<T extends ProcessDataCommon> implements ProcessData<T> {
  private T delegate;
  //Getter & setter
  public ProcessDataGeneric(T delegate) {
    this.delegate = delegate;
  }
}

public class ProcessDataMotorferdsel extends ProcessDataCommon {
  public ProcessDataMotorferdsel() {
    unwrapped = new ProcessDataGeneric<ProcessDataMotorferdsel>(this);
  }
}

我在线得到编译错误:unwrapped = new ProcessDataGeneric<ProcessDataMotorferdsel>(this);

[javac] ProcessDataMotorferdsel.java:52: incompatible types [javac] found : ProcessDataGeneric<ProcessDataMotorferdsel> [javac] required: ProcessData<ProcessDataCommon> [javac]

我无法确定该错误消息的正面或反面。ProcessDataMotorferdsel 类扩展了 ProcessDataCommon,因此 IMO 它应该可以工作。

4

4 回答 4

1

这个答案可能过于简单化,但我认为您问题中的几乎所有代码都会被理想的解决方案消除。对于试图回答这个问题的人来说,问题在于代码试图解决的真正问题并不清楚剩余的内容。

重构 instanceof 的常用方法是将子类与“告诉不问”样式的接口结合使用。如果您可以告诉 ProcessDataGeneric 为您完成整个任务,则无需向 ProcessDataGeneric 询问其委托,如下所示:

public interface ProcessData {
    public <T> T process(Data data);
}

public class ProcessDataGeneric implements ProcessData {
    private ProcessData delegate;

    public ProcessDataGeneric(ProcessData delegate) {
        this.delegate = delegate;
    }

    public <T> T process(Data data) {
        return delegate.process(data);
}

我什至不确定您是否真的需要 ProcessDataGeneric,因为它所做的只是保存真正的 ProcessData 子类:

public class ProcessDataMotorferdsel implements ProcessData {

    // Process the data the Motorferdsel way.
    public <T> T process(Data data) { ... }
}

public class ProcessDataTilskudd implements ProcessData {

    // Process the data the Tilskudd way.
    public <T> T process(Data data) { ... }
}

...然后您可以像这样使用子类:

ProcessData processor = new ProcessDataMotorferdsel();
Result      result    = processor.process(data);

...无需担心代表及其类型。

使用工厂类而不是构造函数来获取子类实例通常会更好,尤其是在需要计算正确的子类时。

于 2010-05-28T08:58:44.413 回答
0

也许我也错过了一些东西,但是

ProcessDataCommon pdc = null;
if(processData.getDelegate() instanceof ProcessDataCommon) {
   pdc = (ProcessDataCommon) processData.getDelegate();
}

应该是等价的..?正如您所提到的,委托始终是ProcessDataCommon类型。

如果ProcessData#getDelegate()然后返回 a ProcessDataCommon,您也可以消除剩余的instanceof检查。

于 2010-05-28T08:54:30.287 回答
0

如果您的对象已经扩展了所需的目标类,则不必强制转换。我的意思是,你可以这样做:

public interface ProcessData {
    public void setDelegate(ProcessDataCommon delegate);
    public ProcessDataCommon getDelegate();
}

还有这个:

public class ProcessDataGeneric implements ProcessData {
    private ProcessDataCommon delegate;
    public ProcessDataGeneric(ProcessDataCommon delegate) {
        this.delegate = delegate;
    }
    @Override
    public ProcessDataCommon getDelegate() {
        return delegate;
    }
    @Override
    public void setDelegate(ProcessDataCommon delegate) {
        this.delegate = delegate;
    }
}

并且您的 instanceof comb 简化为:

ProcessDataCommon pdc = processData.getDelegate();
于 2010-05-28T15:24:55.963 回答
0

我让它工作了。

查看UPDATE #2并包括此更改:

public abstract class ProcessDataCommon<T extends ProcessDataCommon<?>> implements ProcessDataWrapper {
}

使一切编译。

于 2010-05-31T08:48:07.783 回答