用Java重构代码,替换大型if语句

我正在重构我正在研究的项目中的一些代码,并且我遇到了一个跟随格式的大型if / else if语句:

if (changer instanceof AppleChanger) { panel = new ApplePanel(); } else if (changer instanceof OrangeChanger) { panel = new OrangePanel(); } 

现在我的第一个冲动是使用多态来重构它,使它看起来像

 panel = changer.getChangerPanel(); 

但遗憾的是,类包无法访问面板包。

我的下一个冲动是使用重载方法创建一个PanelChooser类:

 PanelChooser.getPanel(changer); //Overloaded Method public Panel getPanel(OrangeChanger changer) { Panel orangePanel = new OrangePanel(); return orangePanel; } public Panel getPanel(AppleChanger changer) { Panel applePanel = new ApplePanel(); return applePanel; } 

这是一个很好的解决方案还是有更好的方法来解决这个问题?

这里的基本“问题”是你有并行的类层次结构。 如果没有一些相当重的重构,你将无法替换if语句。 一些建议在c2维基上 。

您可以做的最好的,也可能是一个非常好的解决方案是将if语句移动到“工厂”类中,并确保它在其他任何地方都不会重复。

我认为你的第一次冲动不起作用很好:)否则你会把你的转换器代码(应该是关于逻辑的东西)耦合到UI代码(面板)并且它的错误。

现在我可以为您提供以下解决方案:

使用方法Panel createPanel创建一个接口PanelCreator,如下所示:

 interface PanelCreator { Panel createPanel(); } 

现在,提供2个实现:

 public class OrangePanelCreator implements PanelCreator{ Panel createPanel() { return new OrangePanel(); } } public class ApplePanelCreator implements PanelCreator { Panel createPanel() { return new ApplePanel(); } } 

现在来到有趣的部分:

创建一个Map,PanelCreator>这将像您的面板的注册表一样:

 Map, PanelCreator> registry = new HashMap<>; registry.put(OrangeChanger.class, new OrangePanelCreator()); registry.put(AppleChanger.class, new ApplePanelCreator()); 

现在,您可以在代码中执行以下操作:

 panel = registry.get(changer.getClass()).createPanel(); 

我认为它会更优雅,因为您可以轻松更改给定更换器的创建者的实现。

希望这可以帮助

如果代码中有多个if / else结构依赖于Changer的实例类型,则可以使用以下访问者模式:

 public interface ChangerVisitor { void visit(OrangeChanger changer); void visit(AppleChanger changer); ... } public class ChangerVisitorEnabler { public static  ChangerVisitorEnabler enable(V) { return new ChangerVisitorEnabler(visitor); } private final V visitor; private ChangerVisitorEnabler(V visitor) { this.visitor = visitor; } public V visit(Charger changer) { if (changer instanceof OrangeChanger) { visitor.visit((OrangeChanger)changer); } else if (changer instanceof AppleChanger) { visitor.visit((AppleChanger)changer); } else { throw new IllegalArgumentException("Unsupported charger type: " + changer); } return visitor; } } 

现在您有一个类型检查代码块和一个类型安全接口:

 public PanelChooser implements ChangerVisitor { public static Panel choosePanel(Changer changer) { return ChangerVisitorEnabler.enable(new PanelChooser()).visit(changer).panel; } private Panel panel; private PanelChooser() { } void visit(OrangeChanger changer) { panel = orangePanel(); } void visit(AppleChanger changer) { panel = applePanel(); } } 

用法很简单:

 panel = PanelChooser.choosePanel(chooser); 

也许你可以这样做:

 public Panel getPanel(Changer changer) { String changerClassName = changer.class.getName(); String panelClassName = changerClassName.replaceFirst("Changer", "Panel"); Panel panel = (Panel) Class.forName(panelClassName).newInstance(); return panel; } 

我不用Java编程,但如果这是在C#中我会尝试。 我也不知道这是否适用于你的包。

祝你好运!

我看不到足够的现有代码和设计。 所以可能,首先我会尝试将面板实例化的代码移动到创建Changer实例的相同位置。 因为选择Panel与选择Changer的决定相同。

如果动态选择了所选的Changer,您可以创建这些面板,然后相应地显示/隐藏它们。

我会做以下事情:

有一个接口PanelChooser与一个方法返回一个面板为Changer。

当Change实现某个类时,让实现ClassBasedPanelChooser返回一个面板,否则返回null。 要返回的类和面板在构造函数中传入。

有另一个实现CascadingPanelChooser,它在构造函数参数中获取PanelChoosers列表,并在调用其方法时要求每个PanelChooser提供一个面板,直到它收到一个非空面板,然后返回该面板。

您的解决方案将无法工作,因为Java会根据编译时类型选择方法(这可能是Changer )。 你可以使用Map, Panel> 如果需要每次都创建新实例Map, Panel> (或Map, Class> )。 如果你需要这个解决方案来工作 – 但是未知 – 例如OrangeChanger子类,这个解决方案确实需要额外的工作。

例如,对于每个Changer子类的单个实例

 changerToPanel.get(changer.getClass()); 

或者如果您需要新实例:

 changerToPanelClass.get(changer.getClass()).newInstance(); 

另一个选择是进行初步预感,让Changer了解Panel。

看看工厂和抽象工厂模式。

工厂模式是一种创建模式,因为它用于控制类实例化。 工厂模式用于替换类构造函数,抽象对象生成过程,以便可以在运行时确定实例化对象的类型。

抽象工厂模式是一种创建模式,因为它用于控制类实例化。 抽象工厂模式用于为客户端提供一组相关或依赖对象。 工厂创建的对象系列在运行时根据具体工厂类别的选择确定。

不要使用instanceof 。 为什么多态失败使用instanceof的唯一地方是equals方法。

回答你的问题。 点击此链接 。 对Cowan和jordao的信贷 。

  • 使用reflection。
 public final class Handler { public static void handle(Object o) { for (Method handler : Handler.class.getMethods()) { if (handler.getName().equals("getPanel") && handler.getParameterTypes()[0] == o.getClass()) { try { handler.invoke(null, o); return; } catch (Exception e) { throw new RuntimeException(e); } } } throw new RuntimeException("Can't handle"); } 
  public static void handle(Apple num) { /* ... */ } public static void handle(Orange num) { /* ... */ } 
  • 责任链
  public abstract class Changer{ private Changer next; public final boolean handle(Object o) { boolean handled = doHandle(o); if (handled) { return true; } else if (next == null) { return false; } else { return next.handle(o); } } public void setNext(Changer next) { this.next = next; } protected abstract boolean doHandle(Object o); } public class AppleHandler extends Changer{ @Override protected boolean doHandle(Object o) { if (!o instanceof Apple ) { return false; } OrangeHandler.handle((Orange) o); return true; } }