Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

Adapterパターン

GoFデザインパターンのAdapterパターンについて。

■概要
ある機能Adapteeに変更を加えることなく新しい機能を追加したい場合の
アダプタを作成して対応するデザインパターン

コンセントと家電の間の電圧変換を行うACアダプタをイメージするのが分かりやすい。

UML
Targetは現状実装したいクラス
AdapterはAdapteeに新しい機能を追加したクラス
Adapteeは既存クラス
ClientはTargetを利用するクラス

  • 継承を利用するパターン

※Targetがインターフェース、Adapteeがクラスの場合に利用

  • 委譲を利用するパターン

※Adaptee、Targetが共にクラスの場合に利用

■具体例

  • 変更前

Html4GeneratorというHTML4形式の文字列出力を管理するクラスにヘッダーの出力を行う
getHeader(String header)というメソッドがあったとします。

    • 旧クラス構成

Html4User.java

/**
 * HTML4出力の利用者です.
 *
 * @author tbpg
 *
 */
public class Html4User {

	/**
	 * HTML4を出力する.
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		Html4Generator html = new Html4Generator();
		System.out.println(html.getHtmlHeader("header"));
	}

}

HtmlGenerator.java

/**
 *  HTML生成インターフェース.
 *
 * @author tbpg
 *
 */
public interface HtmlGenerator {
	/**
	 * HTMLのヘッダーを取得する.
	 *
	 * @param header
	 *                 ヘッダーに表示する内容
	 * @return ヘッダー全体のHTML文字列
	 */
	public String getHtmlHeader(String header);
}

Html4Generator.java

/**
 * HTML4生成クラス.
 *
 * @author tbpg
 *
 */
public class Html4Generator {

	/**
	 * HTML4のヘッダーを取得する.
	 *
	 * <pre>
	 * &lt;div id="header"&gt;headerに指定した変数の内容&lt;/div&gt;
	 * のフォーマットで出力する。
	 * </pre>
	 *
	 * @param header
	 *                 ヘッダーに表示する内容
	 * @return ヘッダー全体のHTML4文字列
	 */
	public String getHtmlHeader(String header) {
		return "<div id=\"header\">" + header + "</div>";
	}

}


例えばヘッダーに「サンプルヘッダー」という値を与えた場合

<div id="header">サンプルヘッダー</div>

という出力になります。

  • 変更後

このメソッドの定義を変えることなくHtml5向けに新しい機能を追加したいという
要求があるとします。
この場合、Html4Generatorで利用していた処理を利用して新しいクラスを作成することによって
既にテスト済みのHtml4Generatorを有効活用して旧バージョンの互換性も残したまま
新たな機能を追加出来るようにHtml4Generatorを継承してHtml5Generatorを作成します。

    • 新クラス構成

Html5User.java

package jp.gr.java_conf.tb.design_pattern.gof23.adapter_pattern;

/**
 * HTML5出力の利用者です.
 *
 * @author tbpg
 *
 */
public class Html5User {

	/**
	 * HTML5を出力する.
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		Html5Generator html = new Html5Generator();
		System.out.println(html.getHtmlHeader("header"));
	}

}

Html5Generator.java

/**
 * HTML5生成クラス.
 *
 * @author tbpg
 *
 */
public class Html5Generator extends Html4Generator {
	/**
	 * HTML5のヘッダーを取得する.
	 *
	 * <pre>
	 * &lt;header id="header"&gt;headerに指定した変数の内容&lt;/header&gt;
	 * のフォーマットで出力する。
	 * </pre>
	 *
	 * @param header
	 *                 ヘッダーに表示する内容
	 * @return ヘッダー全体のHTML5文字列
	 */
	public String getHtmlHeader(String header) {
		String html4Header = super.getHtmlHeader(header);
		return html4Header.replaceAll("div", "header");
	}

}

例えばヘッダーに「サンプルヘッダー」という値を与えた場合

<header id="header">サンプルヘッダー</header>

という出力になります。

Html5UserがClient
HtmlGeneratorがTarget
Html5GeneratorがAdapter
Html4GeneratorがAdaptee
にあたります。


  • まとめ

このように、Adapterパターンを利用することによって旧ロジック自体に修正を行わずに
互換性を残したまま新たな処理を最低限の工数で追加することができます。

  • 参考書籍

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門