概要
Adapterパターンは、既に提供されているクラス等を使いたいがそのままでは使えないとき、必要な形に変換してから利用するための文字通り「アダプター」を提供するデザインパターン。
サンプルプログラム
結城浩先生の増補改訂版Java言語で学ぶデザインパターン入門のJavaプログラムをTypeScriptで写経した。
以下のようなBanner
クラスが用意されているとする。
export class Banner {
private string: string;
public constructor(string: string) {
this.string = string;
}
public showWithParen(): string {
return `(${this.string})`;
}
public showWithAster(): string {
return `*${this.string}*`;
}
}
Banner
は、文字列をカッコでくくって表示するshowWithParen
メソッド、文字列をアスタリスクでくくって表示するshowWithAster
を持つ。
一方で、Bannar
を利用する側でPrint
インターフェースが以下のように宣言されているとする。
interface Print {
printWeak(): string;
printStrong(): string;
}
Print
インターフェースは、文字列を弱く(カッコでくくって)表示するprintWeak
メソッド、文字列を強く(アスタリスクでくくって)表示するprintStrong
メソッドを持つ。
以下のようにアダプターPrintBanner
を使って、(Banner
によって実装された)Print
を利用できるようにしたい。
import { PrintBanner } from 'adapter/inheritance/printBanner';
import { Print } from 'adapter/inheritance/print';
describe('PrintBanner', () => {
const p: Print = new PrintBanner('Hello');
test('printWeak', () => {
expect(p.printWeak()).toEqual('(Hello)');
});
test('printStrong', () => {
expect(p.printStrong()).toEqual('*Hello*');
});
});
PrintBanner
は、Banner
を使ってPrint
インターフェースを実装するためのアダプターである。
継承を使ったAdapterパターンと委譲を使ったAdapterパターンの2パターンを紹介する。
継承を使ったパターン
継承を使ったパターンでは、以下のようにアダプターPrintBanner
クラスを用意する。
import { Banner } from 'adapter/bannar';
import { Print } from 'adapter/inheritance/print';
export class PrintBanner extends Banner implements Print {
public constructor(string: string) {
super(string);
}
public printWeak(): string {
return this.showWithParen();
}
public printStrong(): string {
return this.showWithAster();
}
}
extends
を使いPrintBanner
にshowWithParen
とshowWithAster
を持たせ、それらをprintWeak
、printStrong
として使えるようにしている。
委譲を使ったパターン
Print
がインターフェースではなくクラスだった場合、委譲を使ったパターンを適用できる。
export abstract class Print {
public abstract printWeak(): string;
public abstract printStrong(): string;
}
委譲を使ったパターンでは、以下のようにアダプターPrintBanner
クラスを用意する。
import { Banner } from 'adapter/bannar';
import { Print } from 'adapter/delegation/print';
export class PrintBanner extends Print {
private banner: Banner;
public constructor(string: string) {
super();
this.banner = new Banner(string);
}
public printWeak(): string {
return this.banner.showWithParen();
}
public printStrong(): string {
return this.banner.showWithAster();
}
}
PrintBanner
クラスのプロパティにBanner
のインスタンスbanner
を用意し、それらを使ってprintWeak
、printStrong
を実装している。
考察・感想
テストの内容は、本の中でmainクラスとして書かれている内容をテストの形に落とし込んだもの。本の中のmainクラスでPrintBanner
のインスタンスp
をPrintBanner
型ではなくPrint
型にしているのがなるほどな〜と思った。「pはPrintのプロパティ・メソッドだけを持っていますよ」という意図が示せている。