需要帮助使这些类使用访问者模式和泛型

时间:2010-05-28 08:20:04

标签: java design-patterns generics visitor-pattern

我需要帮助来生成和实现访问者模式。 我们使用了大量的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();
}

我知道有更好的方法可以做到这一点,但我不知道如何利用泛型和访客模式。 非常感谢任何帮助。

更新

我想补充一点,这些类只是一个更大的实现的片段。 ProcessDataProcessDataGeneric是代理人之外的事物(ProcessDataMotorferdsel,依此类推)。代表们都扩展了ProcessDataCommon

我同意重构可能是最好的,但这是2年的生产代码,重构(时间,测试等)代价高昂。但是,我愿意这样做。

更新#2

我试图启动Generic进程,但是我收到了编译错误。这就是它现在的样子。

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 个答案:

答案 0 :(得分:1)

这个答案可能过于简单了,但我认为你问题中的几乎所有代码都会被一个理想的解决方案所淘汰。人们试图回答这个问题的问题是,代码试图解决的真正问题并不清楚是什么遗留问题。

重构instanceof的一种常用方法是将子类与“tell not ask”样式的接口结合使用。如果您可以告诉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);

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

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

答案 1 :(得分:0)

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

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

应该是等价的吗?正如您所提到的,代理始终是ProcessDataCommon类型。

如果ProcessData#getDelegate()会返回ProcessDataCommon,您也可以取消剩余的instanceof支票。

答案 2 :(得分: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;
    }
}

您的梳子实例简化为:

ProcessDataCommon pdc = processData.getDelegate();

答案 3 :(得分:0)

我做到了。

查看更新#2 并包含此更改:

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

让一切都编译好。