这段代码可以用更好,更灵活的方式编写吗?

时间:2012-09-18 09:47:00

标签: java oop

请参阅下面的代码。这里基于String常量,我实例化了不同类型的组件类。现在至少有15种不同类型的String常量。因此,如果我遵循这种模式,将有15种不同的情况和那些很多if -else块。有没有更好的方法呢?我想通过尽可能少的代码更改来灵活地添加和删除案例。

public UIComponent initCellEditor(String editorType) {
        UIComponent editControl = null;
        if ("TbComboBoxCellType".equals(editorType)) {
          editControl = new WebListEntryField();
          editControl.setId("ComboBox");
        } else if ("TbStringCellType".equals(editorType)) {
          editControl = new WebInputEntryField();
          editControl.setId("String");
        } else if ("TbDateCellType".equals(editorType)) {
          editControl = new WebDateEntryField();
          editControl.setId("Date");
        } else if ("TbDateTimeCellType".equals(editorType)) {
          editControl = new WebDateTimeEntryField();
          editControl.setId("DateTime");
        } else {
          //default editor is allways a text input
          editControl = new WebInputEntryField();
          editControl.setId("Input");
        }
        return editControl;
      }

P.S:我们正在使用JDK 6。所以不能使用开启字符串功能。

10 个答案:

答案 0 :(得分:8)

您可以将这些字符串常量转换为枚举,并在枚举上添加构建器方法,例如

public enum CellType {
      TbComboBox {
         @Override
         public UIComponent newComponent() {
            return new xxx();
         }
      },
      TbDate {
         @Override
         public UIComponent newComponent() {
            return new xxx();
         }
      }

      public abstract UIComponent newComponent();
}

这种方法的优点在于它用多态性取代IFs(在我的意见中是非常OO)。


抱歉,我刚才意识到你有一个默认类型(代码中的最后一个),所以你可能需要在某处添加if :(。

答案 1 :(得分:4)

可能:使用Map。只要您将新类型注入Map,即使您创建新类,此方法也有可能工作。它有依赖注入的味道。

package cruft;

import java.util.HashMap;
import java.util.Map;

/**
 * UIComponentFactory description here
 * @author Michael
 * @link
 * @since 9/18/12 5:48 AM
 */
public class UIComponentFactory {
    Map<String, UIComponent> uiComponentMap;
    Map<String, String> uiIdMap;

    public UIComponentFactory(Map<String, UIComponent> uiComponentMap, Map<String, String> uiIdMap) {
        this.uiComponentMap = new HashMap<String, UIComponent>(uiComponentMap);
        this.uiIdMap = new HashMap<String, UIComponent>(uiIdMap);
    }

    public UIComponent initCellEditor(String editorType) {
        UIComponent editControl = null;
        editControl = this.uiComponentMap.get(editorType);
        if (editControl != null) {
            editControl.setId(this.uiIdMap.get(editorType));
        } else {
            editControl = new WebInputEntryField();
            editControl.setId("Input");
        }
        return editControl;
    }
}

答案 2 :(得分:2)

您可以使用枚举:

public static enum Editor {

    TB_COMBOBOX_CELL("tbComboBoxCellType", "ComboBox") {
        public UIComponent getComponent() {
            return new WebListEntryField();
        }
    },
    TB_STRING_CELL("TbStringCellType", "String") {
        //etc
    };
    private final String type;
    private final String id;

    private Editor(String type, String id) {
        this.type = type;
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public String getId() {
        return id;
    }

    public abstract UIComponent getComponent();
    private static Map<String, Editor> types = new HashMap<String, Editor>();

    static {
        for (Editor e : Editor.values()) {
            types.put(e.getType(), e);
        }
    }

    public static Editor getEditor(String type) {
        Editor e = types.get(type);
        if (e == null) return Editor.DEFAULT_EDITOR;
        return e;
    }
}

然后你的方法变成:

public UIComponent initCellEditor(String editorType) {
    Editor e = Editor.getEditor(editorType);
    UIComponent editControl = e.getComponent();
    editControl.setId(e.getId());
    return editControl;
}

答案 3 :(得分:1)

您可以使用Factory模式根据其类型创建对象。例如:

创建一个像这样的工厂类:

public class UIComponentFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(UIComponentFactory.class);

    private static UIComponentFactory instance;

    private static final LinkedHashMap<String, Class> COMPONENTS_MAP = new LinkedHashMap<String, Class>() {{
        put("TbComboBoxCellType", WebListEntryField.class);
        put("TbStringCellType", WebInputEntryField.class);
        put("TbDateCellType", WebDateEntryField.class);
    }};

    private UIComponentFactory() {
    }

    public UIComponent createUIComponent(String type) {
        Class componentClass = COMPONENTS_MAP.get(type);
        Object componentObject = null;
        if (componentClass != null) {
            try {
                componentObject = componentClass.newInstance();
            } catch (InstantiationException ex) {
                LOGGER.error("Instantiation exception occurred", ex);
                throw new SystemException("Instantiation exception occurred", ex);
            } catch (IllegalAccessException ex) {
                LOGGER.error("Illegal access exception occurred", ex);
                throw new SystemException("Illegal access exception occurred", ex);
            }
        }
        return (UIComponent) componentObject;
    }

    public static UIComponentFactory getInstance() {
        if (instance == null) {
            instance = new UIComponentFactory();
        }
        return instance;
    }

}

然后创建组件使用:

UIComponentFactory factory = UIComponentFactory.getInstance();
UIComponent component = factory.createUIComponent("yourComponentType");

这比使用if else语句更有效。

答案 4 :(得分:1)

说实话:不要改变任何东西。有几个选项可以重构此代码,但恕我直言,它们不会提高代码的可读性。坚持if,它并不像他们想要你相信那么邪恶......

答案 5 :(得分:1)

我建议采用基于枚举的方法如下:

enum EditorType {
    TbComboBoxCellType(WebListEntryField.class, "ComboBox"),
    TbStringCellType(WebInputEntryField.class, "String"),
    TbDateCellType(WebDateEntryField.class, "Date"),
    TbDateTimeCellType(WebDateTimeEntryField.class, "DateTime"),
    Generic(WebInputEntryField.class, "Input");

    private final Class<? extends UIComponent> componentType;
    private final String id;

    private EditorType(Class<? extends UIComponent> componentType, String id) {
        this.componentType = componentType;
        this.id = id;
    }

    public static UIComponent createComponent(String editorType) {
        EditorType type;
        try {
            type = valueOf(editorType)
        } catch (IllegalArgumentException e) {
            type = Generic;
        }
        return type.createComponent();
    }

    public UIComponent createComponent() {
        try {
            UIComponent component = componentType.newInstance();
            component.setId(id);
            return component;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

答案 6 :(得分:0)

您不应每次都创建new WebListEntryField();或其他xxEntryField()。创建一个私有字段并返回相同的实例。

答案 7 :(得分:0)

另一种选择是使用枚举来捕获所有

  

CellTypes

和另一个或相同的枚举来获得ID 并使用该枚举来比较输入的输入。

答案 8 :(得分:0)

在枚举上使用开关。将String editorType更改为emum类型。如果无法做到这一点,请将editorType转换为枚举,如following SO question

答案 9 :(得分:0)

您可以使用基于枚举的比较。为不同的输入类型创建不同的枚举,然后使用switch case。

EditorType.java

public enum EditorType {
  COMBO_CELL_TYPE("TbComboBoxCellType"),
  STRING_CELL_TYPE("TbStringCellType"),
  DATE_CELL_TYPE("TbDateCellType"),
  TIME_CELL_TYPE("TbDateCellType"),
  INPUT_CELL_TYPE("TbInputCellType");

  public String value;

  private EditorType(String value) {
    this.value = value;
  }

}

比较使用switch语句。

public UIComponent initCellEditor(EditorType editorType) {
  UIComponent editControl = null;

  switch (editorType) {
    case COMBO_CELL_TYPE:
      // logic here
      break;

    case STRING_CELL_TYPE:

      break;

    case DATE_CELL_TYPE:

      break;

    case TIME_CELL_TYPE:

      break;

    default:
      // default logic
  }
}