ウェブエンジニア珍道中

日々の技術的に関する経験を書いていきます、脱線もします。

typescriptでデザインパターンを書く -Adapter(継承)-

typescriptでデザパタを書いてみます、今回は二回目(一回目で失踪しなくてよかった)

リポジトリはこちら github.com

参考にしている本はこちら

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

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

Adapterパターンとは

「すでに提供されているもの」を「必要なもの」とのズレを埋めて使えるようにするためのものです。

別名Wrapperパターンとも呼ばれていて「包む」とも言われたりするようです。

本の中では

  • コンセントから出てくる交流100Vの電流(すでに提供されているもの)
  • パソコンの充電に使うACアダプター(必要な電流に変換するもの)

を例にあげて説明していました。コンセントの電流とパソコンの充電に必要な電流のズレをACアダプターで埋めているわけですね。これをプログラムの世界にも導入してやろうということです。

サンプル

概要

今回は継承を用いたAdapterパターンの実現をします。委譲を使った方法もあるのでまた後日。

今回の登場人物は4つです。

  • Bannerクラス
    • すでに提供されているものと仮定
    • 自身の持っている文字を()で囲んで表示するメソッドと、*で囲んで表示するメソッドを持つ
  • Printインターフェース
    • 実際にMainクラスから見て使いたいインターフェースを表す(既存のBannerクラスのメソッドは直接使いたくないものとする)
  • PrintBannerクラス
    • Adapterの役割を果たす
    • Bannerクラスを継承・拡張してMainクラスが望む形で()及び**で囲んで表示するメソッドの提供を行う
  • Main(実行ファイル)
    • PrintBannerクラスを使って文字の表示を行う
    • Bannerクラスの存在は知らないし使えないものとする

プログラム

Banner

既存のプログラムと仮定しているクラスです。MainはshowWithParen()showWithAster()メソッドは使いたいけどそのメソッドのままでは使いたくない状態です。

export class Banner {
    private string_: string;

    constructor(string: string) {
        this.string_ = string;
    }

    public showWithParen(): void {
        console.log("(" + this.string_ + ")");
    }

    public showWithAster(): void {
        console.log("*" + this.string_ + "*");
    }
}

Print

Mainクラスからはこのインターフェースを参照してメソッドを使っていきます。

export interface Print {
    printWeak(): void;
    printStrong(): void;
}

PrintBanner

Printインターフェースを実装して、Bannerクラスを継承。Mainから使いやすい状態になるようにしています。このパターンの心臓部です。

import { Banner } from "./banner"
import { Print } from "./print"

export class PrintBanner extends Banner implements Print {
    constructor(string: string) {
        super(string);
    }

    public printWeak(){
        this.showWithParen();
    }

    public printStrong(): void {
        this.showWithAster();
    }
}

Main

import { PrintBanner } from './printBanner'
import { Print } from './print'

const p: Print = new PrintBanner("Hello");

p.printWeak();
p.printStrong();

実行結果

※コンパイル済です

$ node main.js
(Hello)
*Hello*

Main内ではPrintBannerクラスのインスタンスをPrintインターフェースに入れて使用しており、Printインターフェースで宣言されているメソッドのみ気にして使っていれば良い状態となりました。

「Banner何それ美味しいの」状態になっていて、Bannerクラスで宣言されているメソッドは完全に隠れています。

ちょうどパソコンがコンセントから出てくる電流のことは何も把握していないのと同じ状態となりました。

用途

「既存のクラスを使いたいけどそのまま使うのは結構しんどいし、書き直したりするのものな…」という時には、使いやすい形にAdapterを書いてあげれば既存のクラスに手を加えずに容易に使える形になります。

まとめ

シンプルで手軽に使えそうなパターンでした。既存のサービスを拡張する際には使えそうなパターンだと思います。(使い倒さないといけないクラスがあった場合はそのクラス分割したほうが良さげだけど。)

継承を使った実現方法があるので、またまとめ次第記事を上げてリンク貼ります。

今回はこのへんで。ありがとうございました。