Java : まるでプロトタイプベースのような

interfaceとファクトリークラスと無名クラスを組み合わせるパターンです。
JavaScriptの特にJSONでおなじみのオブジェクトの記述(http://jsgt.org/ajax/ref/test/json/test1.htm)を思い出させるものがあります。

      • -

例は、IDのついたオブジェクト(Managable)を、さまざま種類なデータソース(DataSource)から読み出して、同じインターフェースのオブジェクトとして、一つのコンテナ(ManagableContainer)に格納するというものです。
まず、Managableをインターフェースとして定義します。Managableを使う他のプログラマは、このインターフェースだけを見ればよいことになります。いわば、この定義がリファレンスになるわけなので、ここにはなるべく豊富にコメントを付けておくことが望まれます。

public interface Managable {
  String id();
  String name();
  String address1();
  String address2();
  String address3();
}

次に、ManagableContainerをインターフェースとして定義します。これも、Managableと同じことが言えます。コメントをたくさん付けて、他の人が使いやすいようにしておきましょう。

public interface ManagableContainer {
  Managable lookUp(String id);
  Iterator iterator();
}

さて、ここから先が、実装です。まず、Managableの対象となるデータとして、Employee, Companyの2つがあると仮定しておきましょう。それぞれ、独自のIDを持っているのですが、2つの間では排他的に作成しているわけではないので、データの種類が違えば重複が発生します。また、それぞれのデータは、対応するデータソース(EmployeeDataSource, CompanyDataSource)があり、そこからコレクションとして取得されます。

class ManagableContainerFactory {
  private Map dataMap = new HashMap();
  void setUpDataSource(DataSource source) {
    for(Iterator itr = source.iterator();
        itr.hasNext();){
      /* 注:外にif文を書くほうが効率はよいのだが、for文を重複して書く必要があるため見た目が悪い。
       *     これは回避可能だが、論点をずらしたくないので、このままにしておく。
       */
      if (source instanceof EmployeeDataSource) {
        addEmployee((Employee) itr.next());
      }else
      if (source instanceof CompanyDataSource) {
        addCompany((Company) itr.next());
      }else
      { assert false;}
    }
  }
  
  /* ここから個別のオブジェクトを作成するところなのですが、
   * まるでプロトタイプベース(JavaScript)っぽいと思うところです。
   * スロットに関数オブジェクトをくっつけているように見えるんですよね。
   */
  private void addEmployee(final Employee emp) {
    Managable data = new Managable()
      { String id() { return "e" + emp.employee_No();}
        String name() { reutrn emp.full_Name();}
        String address1() { return emp.address_1();}
        String address2() { return emp.address_2();}
        String address3() { return "";} /* Employeeクラスには、住所3がないので */
      }
    dataMap.put(data.id(), data);
  }
  
  private void addCompany(final Company com) {
    Managable data = new Managable()
      { String id() { return "c" + Integer.toString(com.getId());}
        String name() { return com.getName();}
        String address1() { return com.getCountry() + com.getPrefecture();}
        String address2() { return com.getCity() + com.getRestAddress();}
        String address3() { return com.getBuilding();}
      }
    dataMap.put(data.id(), data);
  }
  
  /* ここからコンテナオブジェクトを作成します。
   * 複数回生成する必要がないので、finalメンバとして公開してしまいます。
   */
  final ManagableContainer container = new ManagableContainerImpl();
  class ManagableContainerImpl implements ManagableContainer {
    Managable lookUp(String id) { return (Managable) dataMap.get(id);}
    Iterator iterator() { return dataMap.values().iterator();}
  }
}