用Java重构代码,替代大型if语句
我正在重构一个项目中的一些代码,我遇到了一个大的if/elseif语句,其格式如下:用Java重构代码,替代大型if语句,java,refactoring,Java,Refactoring,我正在重构一个项目中的一些代码,我遇到了一个大的if/elseif语句,其格式如下: if (changer instanceof AppleChanger) { panel = new ApplePanel(); } else if (changer instanceof OrangeChanger) { panel = new OrangePanel(); } 现在我的第一个冲动是使用多态性重构它,使它看起来像 panel = changer.getChangerPanel(
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;
}
这是一个好的解决方案还是有更好的方法解决这个问题?也许您可以:
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实例的同一位置。因为选择一个面板和选择一个转换器是相同的决定
如果动态选择了一个选定的转换器,您可以创建这些面板,然后相应地显示/隐藏它们。我认为您的第一个脉冲不起作用是好的:)否则您会将转换器代码(应该是逻辑代码)与UI代码(面板)耦合,这是错误的 现在,我可以为您提供以下解决方案: 使用方法Panel createPanel创建接口PanelCreator,如下所示:
interface PanelCreator {
Panel createPanel();
}
public interface ChangerVisitor {
void visit(OrangeChanger changer);
void visit(AppleChanger changer);
...
}
public class ChangerVisitorEnabler<V extends ChangerVisitor> {
public static <V extends ChangerVisitor> ChangerVisitorEnabler<V> enable(V) {
return new ChangerVisitorEnabler<V>(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 class OrangePanelCreator implements PanelCreator{
Panel createPanel() {
return new OrangePanel();
}
}
public class ApplePanelCreator implements PanelCreator {
Panel createPanel() {
return new ApplePanel();
}
}
现在是有趣的部分:
创建一个地图,PanelCreator>这将充当面板的注册表:
Map<Class<Changer>, PanelCreator> registry = new HashMap<>;
registry.put(OrangeChanger.class, new OrangePanelCreator());
registry.put(AppleChanger.class, new ApplePanelCreator());
我认为它将更加优雅,因为您可以在给定更改器的情况下轻松更改创建者的实现
希望这有帮助这里的基本“问题”是您有并行类层次结构。如果不进行一些相当繁重的重构,您将无法替换if语句。以下是一些建议
您所能做的最好的,也可能是一个非常好的解决方案,就是将if语句移动到一个“factory”类中,并确保它不会复制到其他任何地方。您的解决方案将不起作用,因为Java根据compiletime类型选择方法(这里可能是
Changer
)。您可以使用Map查看和模式
工厂模式是一种创造性的模式,因为它用于控制类实例化。工厂模式用于替换类构造函数,抽象对象生成过程,以便在运行时确定实例化对象的类型
抽象工厂模式是一种创造性模式,用于控制类实例化。抽象工厂模式用于向客户机提供一组相关或从属对象。工厂创建的对象族在运行时根据具体工厂类的选择确定。我将执行以下操作:
有一个接口PanelChooser,它使用一个方法为转换器返回一个面板
让实现ClassBasedPanelChooser在更改实现某个类时返回面板,否则返回null。将要返回的类和面板传递到构造函数中
使用另一个实现CascadingPanelChooser,它在构造函数参数中获取PanelChooser列表,并在调用其方法时要求每个PanelChooser提供一个面板,直到它接收到一个非空面板,然后返回该面板。不要使用instanceof。
唯一可以使用instanceof的地方是equals方法内部
回答你的问题。跟着这个。
归功于和
- 使用反射。
- 责任链
如果代码中存在多个依赖于转换器实例类型的If/else构造,则可以使用如下访问者模式:
interface PanelCreator {
Panel createPanel();
}
public interface ChangerVisitor {
void visit(OrangeChanger changer);
void visit(AppleChanger changer);
...
}
public class ChangerVisitorEnabler<V extends ChangerVisitor> {
public static <V extends ChangerVisitor> ChangerVisitorEnabler<V> enable(V) {
return new ChangerVisitorEnabler<V>(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;
}
}
用法非常简单:
panel = PanelChooser.choosePanel(chooser);
我怀疑第二个方法不起作用,因为您必须显式地将转换器转换为java的子类,以标识要调用的方法。也许你可以使用注册表类/映射(这样就可以将更改器映射到面板并查找传递的实例)。为什么你的类名以小写开头?@U Mad Thank,这是我的错别字,fixedOk,但这需要你的类的命名约定;每个xyzChanger
类必须有一个xyzPanel
。而且它并不是真正的类型安全,因为有一个转换到面板那里。IMHO,最好避免对类名进行这样的操作,因为它不是唯一的选项。它更难维护,例如,类名更改不会导致任何编译错误。是的,这将是一种命名约定。公约应该加速发展。但是,getPanel
应该可以覆盖,以防您想要更改某些更改器的约定。如果你想知道的话,这将是抽象工厂设计模式。这很有趣,我将搜索是否可以用Java实现它,谢谢。那已经是Java了,除非我在某个地方犯了错误:-)一个很好的快速解决方案,但是,如果有人添加了一个子类,例如OrangeChanger,那么它将不起作用。您认为在这种情况下,注册表应该通过附加的“put”调用进行更新吗?您可以这样做,但您违反了Liskov替换原则。就实现相同结果所花费的代码行数而言,与if语句相比没有任何优势。理论上你是对的,但这里的问题是创建这样的子类型是否合理。您也说得对,当前的实现没有优势,但主要思想是将面板的条件创建逻辑与转换器解耦。在实际情况下,最好的设计不是简单的映射,而是更高级的配置(可能是基于xml的spring或其他配置)。在中国科学院
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;
}
}
public interface ChangerVisitor {
void visit(OrangeChanger changer);
void visit(AppleChanger changer);
...
}
public class ChangerVisitorEnabler<V extends ChangerVisitor> {
public static <V extends ChangerVisitor> ChangerVisitorEnabler<V> enable(V) {
return new ChangerVisitorEnabler<V>(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);