web-dev-qa-db-ja.com

JavaでファクトリにEnumを使用することは、ベストプラクティスですか?

Javaを使用すると、Enumにデータと動作を埋め込むことができます。 Enumにファクトリーを直接実装したくないので、これはその役割ではないと思います。

しかし、列挙型にクラス参照を配置し、外部ファクトリにオブジェクトを構築することができます。伝統的な工場のパターンと比較して、あなたにとって最良の実装は何ですか?どの場合にどのソリューションを使用する方が良いですか?

さて、コード。

オブジェクトを構築するために両方のソリューションで使用される関数。必要に応じて、マップにフライウェイトパターンを実装するのに役立ちます。

private Action getAction(Class<? extends Action> actionClazz) {
    // logger + error handling
    return actionClazz.newInstance();
}

1)伝統的な工場で:

public enum ActionEnum {
    LOAD_DATA,
    LOAD_CONFIG;
}

public Action getAction(ActionEnum action) {
    switch (action) {
    case LOAD_CONFIG:
        return getAction(ActionLoadConfig.class);
    case LOAD_DATA:
        return getAction(ActionLoadData.class);
    }
}

2)Enumスタイルのファクトリーの場合:

public enum ActionEnum {
    LOAD_DATA(ActionLoadConfig.class),
    LOAD_CONFIG(ActionLoadData.class);

    public ActionEnum(Class<? extends Action> clazz){...}
    public Class<? extends Action> getClazz() {return this.clazz}
}

public Action getAction(ActionEnum action) {
    return getAction(action.getClazz());
}
25
airdump

2番目のものはよりクリーンです。長いswitchブロックを必要とせず、最初の値のようにenum値の1つを忘れるリスクがありません。

ただし、列挙型はアクションのファクトリーと組み合わせるべきではない一般的な列挙型(Monthなど)になる可能性があるため、常に使用できるとは限りません。

18
JB Nizet

IMOのnewInstance()の呼び出しは、Java(javadocを読む)によって提供されるコンパイル時の保護のいくつかを露骨に無効にし、新しいExceptionsを処理します。

これが Sergeyが提供したもの に似たソリューションです。機能的なインターフェイスとメソッド参照のおかげで、もう少し簡潔になっています。

public enum ActionEnum {
  LOAD_DATA(ActionLoadData::new),
  LOAD_CONFIG(ActionLoadConfig::new)

  private Supplier<Action> instantiator;

  public Action getInstance() {
    return instantiator.get();
  }

  ActionEnum(Supplier<Action> instantiator) {
    this.instantiator = instantiator;
  }
}

public Action getAction(ActionEnum action) {
  return action.getInstance();
}
14
OneWholeBurrito

これは私にとってはうまくいきます:

 enum ActionEnum
    {
      LOAD_DATA {

        @Override
        public ActionLoadData getInstance() {
            return new ActionLoadData ();
        }

    },
    LOAD_CONFIG {

        @Override
        public ActionLoadConfig getInstance() {
            return new ActionLoadConfig();
        }

    };

    public abstract ILightBulb getInstance();
}

class ActionFactory
{
    public  Action getAction(ActionEnum action)
    {
       return action.getInstance();
    }
}
14
Serg Burlaka

さらに分離するには:

static final EnumMap<ActionEnum, Class<? extends Action>> enumToClass = new EnumMap<>();
static
{  
    enumToClass.put(ActionEnum.LOAD_DATA, ActionLoadData.class);
    etc...
}


public Action getAction(ActionEnum action) 
{
    return getAction(enumToClass.get(action));
}

EnumMapは非常に高速なので、心配する必要はありません。

7
ZhongYu