2

请看下面的代码。这里基于字符串常量,我实例化了不同类型的组件类。现在至少有 15 种不同类型的字符串常量。因此,如果我遵循这种模式,将会有 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;
      }

PS:我们使用的是 JDK 6 。所以不能使用切换字符串功能。

4

10 回答 10

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)。


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

于 2012-09-18T09:54:26.717 回答
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;
    }
}
于 2012-09-18T09:53:38.140 回答
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;
}
于 2012-09-18T09:59:17.067 回答
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语句更有效的方法。

于 2012-09-18T09:57:11.167 回答
1

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

于 2012-09-18T10:00:23.607 回答
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);
        }
    }

}
于 2012-09-18T10:01:33.400 回答
0

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

于 2012-09-18T09:51:21.057 回答
0

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

细胞类型

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

于 2012-09-18T09:52:40.667 回答
0

使用枚举开关。更改String editorType为 emum 类型。如果这是不可能的,请按照以下 SO questioneditorType转换为枚举。

于 2012-09-18T09:55:53.410 回答
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
  }
}
于 2012-09-18T11:13:51.447 回答