2

プラグ可能なインターフェイスのファクトリを設計しようとしています。ファクトリ インスタンスを取得すると、ファクトリはその特定の実装に適切なサブクラスを返すという考え方です。

この場合、サブクラスではなく文字列を使用して ID コードを表すサード パーティ ライブラリをラップしています。したがって、ライブラリをラップする実装では、すべての実装クラスにgetCode()インターフェイス API で明示的に必要とされないメソッドがあります。enumコードとインターフェイス クラス間のこのマッピングを格納するために を使用しています。

ほとんどの場合、このgetCode()メソッドは必要ありません。ただし、実装パッケージのごく一部の状況で、そのメソッドにアクセスする必要があります。したがって、私の問題は、特定の Factory 実装への参照がある場合にメソッドが存在することを呼び出し元に伝える Factory 実装の署名を持たせたいことgetCodeです。

以下は、状況をsscceに消化するために最善を尽くした多くのコードです。非常に長いことは承知していますが、見た目よりも単純で、sscce の単語の 1 つに「完全」があります。

公開 API:

public interface Factory {
  public <T extends IFoo> T makeIFoo(Class<T> klass);
}

public interface IFoo {
  void doSomething();
}

public interface IFooBar extends IFoo {
  void doBarTask();
}

public interface IFooBaz extends IFoo {
  void doBazTask();
}

ユースケースの例:

public class SomeClass {
  private Factory myFactory; 

  public void doSomething() {
    IFooBar ifb = myFactory.create(IFooBar.class);
  }
}

実装の SSCCE バージョン:

interface ICode {
  String getCode();
}

abstract class BaseCode implements IFoo, ICode {
  private String code;

  BaseCode(String code) {
    this.code = code;
  }

  @Override
  public String getCode() {
    return code;
  }

  @Override
  public void doSomething() {
    System.out.println("Something");
  }
}

class FooBarImpl extends BaseCode implements ICode, IFooBar {
  FooBarImpl(String code) {
    super(code);
  }

  @Override
  public void doBarTask() {
    System.out.println("BarTask");
  }
}

class FooBazImpl extends BaseCode implements ICode, IFooBaz {
  FooBazImpl(String code) {
    super(code);
  }

  @Override
  public void doBazTask() {
    System.out.println("BarTask");
  }
}

列挙型コードマッパー:

static enum CodeMap {
  FOOBAR ("A", IFooBar.class) {
    FooBarImpl create() { return new FooBarImpl(getCode()); }
  },
  FOOBAZ ("B", IFooBaz.class) {
    FooBazImpl create() { return new FooBazImpl(getCode()); }
  };

  private static Map<Class<? extends IFoo>, CodeMap> classMap;
  static {
    classMap = new HashMap<Class<? extends IFoo>, CodeMap>();
    for(CodeMap cm : CodeMap.values()) {
      classMap.put(cm.getFooClass(), cm);
    }
  }

  private String code;
  private Class<? extends IFoo> klass;

  private CodeMap(String code, Class<? extends IFoo> klass) {
    this.code = code;
    this.klass = klass;
  }

  String getCode() {
    return code;
  }

  Class<? extends IFoo> getFooClass() {
    return klass;
  }

  static CodeMap getFromClass(Class<? extends IFoo> klass) {
    return classMap.get(klass);
  }

  abstract BaseCode create();
}

実装パッケージ内のサンプル ユース ケース:

public class InternalClass {
    CodeFactory factory;

    public void doSomething() {
        FooBarImpl fb = factory.makeIFoo(IFooBar.class);
    }
}

工場での試み:

これは、リターンが常に実装されることを指定するものではありませんICode。しかし、渡されたインターフェイス クラスは を実装ICodeしていません。それが要点です。

class CodeFactory implements Factory {
  @Override
  public <T extends IFoo> T makeIFoo(Class<T> klass) {
    CodeMap map = CodeMap.getFromClass(klass);

    if (map == null) return null; // Or throw an exception, whatever, SSCCE

    return (T) map.create();
  }
}

私は何をすべきか?

4

2 に答える 2