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

发布于 2024-09-02 22:59:11 字数 3156 浏览 2 评论 0原文

我需要帮助来泛化和实现访问者模式。 我们使用了大量的instanceof,这很痛苦。我确信它可以修改,但我不知道如何修改。

基本上我们有一个接口 ProcessData

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

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

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

我尝试启动通用进程,但是遇到编译错误。这就是现在的样子。

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(this);

[javac] ProcessDataMotorferdsel.java:52: 不兼容的类型 [javac] 发现:ProcessDataGeneric[javac] 必需:ProcessData[javac]

我无法弄清楚该错误消息。 ProcessDataMotorferdsel 类扩展了 ProcessDataCommon,因此 IMO 它应该可以工作。

I need help to generify and implement the visitor pattern.
We are using tons of instanceof and it is a pain. I am sure it can be modified, but I am not sure how to do it.

Basically we have an interface ProcessData

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

Now we have a class ProcessDataGeneric that implements ProcessData

public class ProcessDataGeneric implements ProcessData {
  private Object delegate;

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

Now a new interface that retrieves the ProcessData

interface ProcessDataWrapper {
  public ProcessData unwrap();
}

Now a common abstract class that implements the wrapper so ProcessData can be retrieved

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

  public ProcessData unwrap() {
    return unwrapped;
  }
}

Now the implementation

public class ProcessDataMotorferdsel extends ProcessDataCommon {

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

similarly

public class ProcessDataTilskudd extends ProcessDataCommon {

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

Now when I use these classes, I always need to do instanceof

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

I know there is a better way to do this, but I have no idea how I can utilize Generics and the Visitor Pattern.
Any help is GREATLY appreciated.

UPDATE

I want to add that these classes are just snippets of a much larger implementation.
The ProcessData and ProcessDataGeneric is something that is outside of the delegates (ProcessDataMotorferdsel and so on). The delegates all extends ProcessDataCommon.

I can agree that a refactoring is probably best to do, but this is production code that is 2 years old, and it is costly to refactor (time,testing, etc). However, I am willing to do it.

UPDATE #2

I have tried to start the Generic process, however I am getting compile error. This is how it looks now.

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);
  }
}

I get compile error on line: unwrapped = new ProcessDataGeneric<ProcessDataMotorferdsel>(this); Saying

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

I cannot make heads or tails of that error message. The ProcessDataMotorferdsel class extends ProcessDataCommon, so IMO it should work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

演出会有结束 2024-09-09 22:59:11

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

重构 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);

...而不必担心委托及其类型。

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

This answer is probably over-simplistic, but I think that nearly all of the code in your question would be eliminated by an ideal solution. The problem for people trying to answer the question is that the real problem that the code is trying to solve isn't clear from what is left over.

A common approach to refactoring away instanceof is to use sub-classes in conjunction with a "tell not ask" style of interface. There is no need to ask ProcessDataGeneric for its delegate if you can tell ProcessDataGeneric to do the whole task for you, like this:

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);
}

I'm not even sure that you really need ProcessDataGeneric, since all it does is hold the real ProcessData sub-class:

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) { ... }
}

... and then you can use the sub-classes like this:

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

... without having to worry about delegates and what type they are.

It is often better to use a factory class instead of a constructor to obtain the sub-class instance, particularly if the correct sub-class needs to be calculated.

李白 2024-09-09 22:59:11

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

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

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

如果 ProcessData#g​​etDelegate() 返回一个 ProcessDataCommon,您也可以消除剩余的 instanceof 检查。

Maybe I'm missing something too, but

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

should be equivalent..? As you mentioned, the delegate is always ProcessDataCommon type.

If ProcessData#getDelegate() would then return a ProcessDataCommon, you could eliminate the remaining instanceof check too.

白昼 2024-09-09 22:59:11

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

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();

You don't have to cast if your object already extends the desired target class. I mean, you can do this:

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

and this:

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;
    }
}

And your instanceof comb simplifies to:

ProcessDataCommon pdc = processData.getDelegate();
沉睡月亮 2024-09-09 22:59:11

我成功了。

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

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

使所有内容都编译。

I made it work.

Look at UPDATE #2 and including this change:

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

Made everything compile.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文