SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

デザインパターンの使い方

デザインパターンの使い方: Builder

インターフェイスと実装の分離を実現するBuilderパターン

  • このエントリーをはてなブックマークに追加

 Builderパターンは、Template Methodパターンによく似ています。Template Methodパターンとの大きな違いは、その目的がオブジェクトを生成することであり、アルゴリズムを実行することではないという点です。Builderパターンは、役割分担を明確にするだけでなく、インターフェイスと実装の分離を実現する代表的な事例であり、パターンを使用しない場合に起こりうる重複をかなりの程度防ぐことができます。

  • このエントリーをはてなブックマークに追加

Builderパターンの例

 図書館の所蔵目録(カタログ)は、書籍や映画などさまざまな資料の集合体です(リスト1を参照)。図書館ではいろいろなレポートを頻繁に印字しますが、まず考えられるのは、館内のすべての資料を一覧にして種類ごとにソートした所蔵資料レポートです(きっと相当に膨大なレポートになるでしょう)。

リスト1 基本的な資料クラス
// Material.java:
public class Material {
   private String classification;
   private String title;
   private String director;
   private String year;

   public Material(String classification, String title,
                   String director, String year) {
      this.classification = classification;
      this.title = title;
      this.director = director;
      this.year = year;
   }

   public String getAuthor() {
      return director;
   }

   public String getClassification() {
      return classification;
   }

   public String getTitle() {
      return title;
   }

   public String getYear() {
      return year;
   }
}

// Book.java:
public class Book extends Material {
   public Book(String classification, String title,
               String author, String year) {
      super(classification, title, author, year);
   }
   // ...
}

// Movie.java:
public class Movie extends Material {
   public Movie(String classification, String title,
                String director, String year) {
      super(classification, title, director, year);
   }

   public String getDirector() {
      return getAuthor();
   }
   // ...
}

 Catalogクラスは、各種資料のシンプルなコンテナです。リスト2をご覧ください。

リスト2: Catalogクラス
package builder;

import java.util.*;

public class Catalog implements Iterable<Material> {
   private List<Material> materials = new ArrayList<Material>();

   public void add(Material material) {
      materials.add(material);
   }

   public List<Material> materials() {
      return materials;
   }

   @Override
   public Iterator<Material> iterator() {
      return materials.iterator();
   }
}

 レポートはシンプルな生成プロセスを使用して作られます。はじめに、資料の一覧を種類ごとにグループ化して(たとえば、最初に書籍、次に映画のように)ソートします。レポートには適切なヘッダーを印字します。次に、ソートした所蔵資料の一覧全体について繰り返し処理を行い、各行を出力していきます。最後に、レポートの末尾に適切な補足情報を印字します。

 リスト生成の各ステップの詳細は状況により変わってきます。たとえば、Webレポートでは適切なHTMLタグが必要です。あるいは、横幅に制約のあるプリントアウト(明細書など)では、おそらくいくつかのフィールドの割愛や、アウトプットの再レイアウトが必要でしょう。

 Builderパターンは、こうしたレポート作成機能の設計を取りまとめるための理想的な手段を提供します。Builderパターンでは、クライアントがオブジェクトの種類と内容を指定するという方法で複雑なオブジェクトの生成を制御します。このクライアントは「ディレクター(director)」と呼ばれ、実装の詳細を一切指定しません。実装の詳細は別のビルダー階層の担当になります。

 リスト3に、ディレクタークラスを示します。ディレクターオブジェクトの生成アルゴリズムは、generateメソッドの1行として表現されます。つまり、まずCatalogオブジェクトをsort関数でソートし、それを適切なビルダーオブジェクトと共にcreateReportメソッドに引き渡します。createReport内のコードでは、ビルダーオブジェクトへのコールバックを何度か行います。具体的には、builderに対してまずヘッダーの生成を要求し、次に各資料に対応するオブジェクトの詳細なアウトプットの生成を要求し、最後にフッターの生成を要求します。このcreateReportメソッドが生成アルゴリズムの「シェル」に該当します。

 最終的には、ビルダーがgetReportメソッドによってレポートを出力します。ディレクターは、このレポートを呼び出し側のクライアントへ返します。

リスト3 ディレクターの例
import java.util.*;

public class CatalogReportDirector {
   private final Catalog catalog;

   public CatalogReportDirector(Catalog catalog) {
      this.catalog = catalog;
   }

   public String generate(CatalogReportBuilder builder) {
      return createReport(builder, sort(catalog));
   }

   private List<Material> sort(Catalog catalog) {
      List<Material> catalogCopy =
         new ArrayList<Material>(catalog.materials());
      Collections.sort(catalogCopy, new Comparator<Material>() {
         @Override
         public int compare(Material material1,
                            Material material2) {
            if (material1.getClass() == material2.getClass()) {
               if (material1.getTitle().
                  equals(material2.getTitle()))
                  return material1.getAuthor().
                     compareTo(material2.getAuthor());
               return material1.getTitle().
                  compareTo(material2.getTitle());
            }
            return material1.getClass().getName().compareTo(
                  material2.getClass().getName());
         }
      });
      return catalogCopy;
   }

   private String createReport(CatalogReportBuilder builder,
         List<Material> sortedCatalog) {
      builder.generateHeader();
      for (Material material: sortedCatalog)
         builder.generateDetail(material);
      builder.generateSummary();
      return builder.getReport();
   }
}

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
デザインパターンの使い方連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Jeff Langr(Jeff Langr)

本格的なソフトウェアの開発に四半世紀以上携わってきたベテランのソフトウェア開発者。『Agile Java: Crafting Code With Test-Driven Development』(Prentice Hall、2005年)と、他の1冊の著書がある。『Clean Code』(Uncle Bob Martin著、Prentice Hall、2008年8月)にも寄稿している。また、ソフトウェア開発に関する記事を80件以上執筆しており、そのうちの...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/3012 2008/09/30 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング