如何使用Visitor模式替换"instanceof"

Dra*_*gon 5 java polymorphism gwt instance

我对访问者模式有点不友好,但我有一个需要访问者实现的任务(如果我想避免"instanceof"检查).

我有一个类,它是几个gwt元素的包装:Label,Panel,Widget(可以是复选框,列表框,文本框等).我使用数组作为UI的相似部分的集合.例如Label +复选框,Label +文本框; 标签+按钮等

一些元素以不同的方式构造(从例如Panel派生的另一个类的一部分).因此,我有两个相同的构造函数,但在一个地方使用重载方法.我可以合并这些构造函数并使用上面提到的方法中的"instanceof"检查元素.但我不喜欢这个解决方案,并希望使用访问者模式替换它.说实话,我不知道该怎么做,希望对你有所帮助.

这是我的一个例子:

public class MyWidgets {
    private String stringLabel;
    private Widget widget;
    private Panel panel;

    public MyWidgets(String stringLabel, Widget widget) {
      this.stringLabel = stringLabel;
      this.widget = widget;

      initPanel(stringLabel, widget);
    }

    public MyWidgets(ConstructedClass cs, Widget widget) {
       this.widget = widget;

       initPanel(cs, widget);
    }

    private initPanel(String label, Widget widget) {
      panel = SomeStaticUtilityClass.initPanel(new Label(label), widget);
    }

    private initPanel(ConstructedClass cs, Widget widget) {
      panel = SomeStaticUtilityClass(cs, widget);
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样的东西(我试图让它最大化抽象,实际上它更难).

所以我有一个使用"instanceof"的解决方案:

private initPanel(Object object, Widget widget) {
  if(object instanceof String) {
    panel = SomeStaticUtilityClass.initPanel(new Label(label), widget);
  }
  if(object instanceof ConstructedClass) {
    panel = SomeStaticUtilityClass.initPanelFromObject(cs, widget);
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望从"instanceof"中保存并只保留一个构造函数,如果可能的话,甚至可以使用一个没有重载版本的init方法.提前感谢您的建议和帮助.

PS>我再说一遍,上面的类是捏造的,看起来像是一些误解,尤其是这个String标签:)

JB *_*zet 3

IMO,您现有的解决方案(带有两个构造函数)就很好。

您可以使用策略模式并让构造函数采用某个PanelProvider接口的实例而不是对象。该接口将具有以下方法:

Panel createPanel(Widget widget);
Run Code Online (Sandbox Code Playgroud)

。客户端会将一个实例StringPanelProvider或一个实例传递ConstructedClassPanelProvider给构造函数。您的构造函数将如下所示:

public MyWidgets(PanelProvider panelProvider, Widget widget) {
   this.widget = widget;
   this.panel = panelProvider.createPanel(widget);
}
Run Code Online (Sandbox Code Playgroud)

StringPanelProvider 实现看起来像

public class StringPanelProvider implements PanelProvider {

    private String s;

    public StringPanelProvider(String s) {
        this.s = s;
    }

    @Override
    public Panel createPanel(Widget widget) {
        return SomeStaticUtilityClass.initPanel(new Label(s), widget);
    }
}
Run Code Online (Sandbox Code Playgroud)

ConstructedClassPanelProvider 看起来是一样的。

如果您确实想使用访问者模式,那么您必须稍微修改上面的内容:

public interface Visitable {
    void accept(Visitor visitor);
}

public interface Visitor {
    void stringVisited(String s);
    void constructedClassVisited(ConstructedClass cs);
}

public class StringVisitable {
    private String s;

    public StringVisitable(String s) {
        this.s = s;
    }

    void accept(Visitor visitor) {
        visitor.stringVisited(s);
    }
}

// similar for ConstructedClassVisitable

public MyWidgets(Visitable visitable, final Widget widget) {
   this.widget = widget;
   visitable.accept(new Visitor() {
       public void stringVisited(String s) {
           panel = SomeStaticUtilityClass.initPanel(new Label(label), widget);
       }

       public void constructedClassVisited(ConstructedClass cs) {
           panel = SomeStaticUtilityClass.initPanelFromObject(cs, widget);
       }
   });
}
Run Code Online (Sandbox Code Playgroud)

但这对我来说似乎是过度设计。