用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
如果需要每次都创建新实例Map
(或Map
)。 如果你需要这个解决方案来工作 – 但是未知 – 例如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; } }