2

以下のコードを参照してください。ここでは 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;
      }

PS: JDK 6 を使用しています。そのため、文字列機能のスイッチを使用できません。

4

10 に答える 10

8

you could transform those string constants to Enums, and add a builder method on the enum, for example

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

      public abstract UIComponent newComponent();
}

The beauty of this approach is that it replaces IFs with polymorphism (which in my opnion is very OO).


Sorry, I just realised that you have a default type (the last else in your code), so you might need to add an if somewhere :(.

于 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

別のオプションは、列挙型を使用してすべてをキャプチャすることです

CellTypes

別のまたは同じ列挙型を使用してIDを取得し、その列挙型を使用して入力を比較します。

于 2012-09-18T09:52:40.667 に答える
0

You should not create new WebListEntryField(); or other xxEntryField() each time. Create a private field and return the same instance.

于 2012-09-18T09:51:21.057 に答える
0

列挙型のスイッチを使用します。String editorTypeemum型に変更。これが不可能な場合は、次の SO questioneditorTypeのように列挙型に変換します。

于 2012-09-18T09:55:53.410 に答える
0

列挙型ベースの比較を使用できます。入力タイプごとに異なる列挙型を作成し、大文字小文字の切り替えを使用します。

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 に答える