1 2 →

Prototypeパターンの例

 図書館の職員が図書館システムにたくさんの新しい本と映画ソフトを追加しているところを想像してみてください。職員は、スキャナを使って本に付けられたバーコードを読み取ります(話を簡単にするために、バーコードは本の分類番号と同じであるとしておきましょう)。

 その本が、図書館に追加される最初の1冊である場合、システムは外部API呼び出しを行って、本の著者(映画の場合は監督)、タイトル、出版年などの基本情報を確認します。この検索にはとても時間がかかります。さらに、職員は返ってきた情報を目で見て確認し、誤りがあれば修正しなければなりません。

 リスト1は、このような要件に基づいた所蔵目録(カタログ)の実装を示しています。このテストは、本や映画のオブジェクトを作成し、これらのオブジェクトに適切なデータを設定するという作業をクライアントコードが担当することを示しています。ここでは、このクライアントから外部API呼び出しを行うと仮定しましょう。資料オブジェクトが作成されると、クライアントコードはaddNewを呼び出してそのオブジェクトを所蔵目録に追加します。

リスト1 単純な所蔵目録
// CatalogTest.java
import static org.junit.Assert.*;

import java.util.*;
import org.junit.*;

public class CatalogTest {
   private Catalog catalog;

   @Before
   public void initialize() {
      catalog = new Catalog();
   }

   @Test
   public void isEmptyOnCreation() {
      assertEquals(0, catalog.size());
   }

   @Test
   public void addNewBook() {
      final Book book = new Book("QA123", "author", "title",
                                 "1999", 1);
      catalog.addNew(book);
      assertEquals(1, catalog.size());
      List<Material> materials = catalog.get("QA123");
      assertEquals(1, materials.size());
      assertSame(book, materials.get(0));
   }
}

// Catalog.java
import java.util.*;

public class Catalog {
   private MultiMap<String, Material> materials =
      new MultiMap<String, Material>();

   public int size() {
      return materials.valuesSize();
   }

   public void addNew(Material material) {
      materials.put(material.getClassification(), material);
   }

   public List<Material> get(String classification) {
      return materials.get(classification);
   }
}

 追加される資料の多くは重複しており、重複している資料の場合、登録すべき情報はすべて同じです(そのため、このような資料については情報を確認する必要はないだろうと皆さんなら考えますね)。この所蔵目録では、既に存在している資料の複製(つまりプロトタイプ)を作成し、API呼び出しを回避するようにします。

 リスト2のテストのシナリオはこうです。まず1冊目の本の情報が外部で作成され、所蔵目録に追加されます。続いて2冊目の本がスキャンされます。スキャンされた分類は、既にシステムに存在するものであるため、クライアントは分類だけを渡してaddCopyを呼び出します。1冊目の本を検索し、その情報を使用してコピーを作成する処理は、所蔵目録が内部的に行います。

リスト2 重複する本を追加するテスト
@Test
public void addCopyViaPrototype() {
   final Book book = new Book("QA123", "title", "author",
                              "1999", 1);
   catalog.addNew(book);

   catalog.addCopy("QA123");

   assertEquals(2, catalog.size());

   List<Material> materials = catalog.get("QA123");
   assertEquals(2, materials.size());
   assertSame(book, materials.get(0));

   Material copy = materials.get(1);
   assertTrue(copy instanceof Book);
   assertEquals("QA123", copy.getClassification());
   assertEquals("author", copy.getAuthor());
   assertEquals("title", copy.getTitle());
   assertEquals("1999", copy.getYear());
   assertEquals(2, copy.getCopyNumber());
}

 リスト3は、これらのテストをパスする程度には整った、簡単な実装を示しています。ただし、これはあまり良い実装とはいえません。冊数を取得するアルゴリズムには問題があるかもしれませんが、ここでは気にしないでください。本当に問題なのは、copyメソッドが不恰好なものになるだろうということです。このテストを本だけでなく映画にも適用しようと思うと、copyメソッドには資料のタイプを確認するためのif文が必要になります。さらに、さまざまなオブジェクトタイプの構造を詳細に記述していけば、コードは煩雑になっていくでしょう。BookオブジェクトやMovieオブジェクトの構造が変更されれば、Catalogクラスも影響を受けます。

リスト3 リスト2のテストをパスする実装
public void addCopy(String classification) {
   List<Material> copies = materials.get(classification);
   ''materials.put(classification, copy(copies.get(0)));''
}

''private Material copy(Material material) {
   Book book = new Book(material.getClassification(),
         material.getTitle(),
         material.getAuthor(),
         material.getYear(),
         material.getCopyNumber() + 1);
   return book;
}''

1 2
→
INDEX
デザインパターンの使い方: Prototype
Page1
Prototypeパターンの例
プロフィール
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件以上執筆しており、そのうちの35件以上を Developer.comで読むことができる。さらに詳しくは、個人サイト(http: //langrsoft.com)を参照。メールの宛先はjeff at langrsoft dot com。


プロフィール
japan.internet.com ジャパンインターネットコム

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


注目の求人情報
機械・電気・回路設計/株式会社デンソー
カーエレクトロニクスの進化を支える車載用カスタムICの開発・設計を担当していただきます。 ...
システムエンジニア/商社系SIベンダー
・Windows、UNIXでの情報系システムの開発・・保守 ・お客様との打ち合わせを通じて要件定義、設計、実...
コンサルタント/国内大手シンクタンク
業務コンサルティング及びITコンサルティング

(最新日付順)
名前(ゲストの方もコメントをどうぞ):*
アイコン:
なし

内容(テキストのみ1200文字まで):*

投稿規定に同意して

スポンサーサイト

この記事のトラックバックURL: