【TS】今さら聞けないファサードパターン


はじめに

今回はファサードパターン(Facade Pattern)について解説します。
名前そのものは知らなくとも、知らず知らずのうちに使用していることが多いデザインパターンです。

ファサードパターンとは?

TECHSCOREさんの解説があります。

以下、引用です。

プログラムを作っていくと、最初は小さなものでも、だんだん大きくなっていきます。 たくさんのクラスが出来て、相互に関係しあい、複雑になっていきます。 クラスを使う場合には、それらの関係を正しく理解して、 正しい順番にメソッドを呼び出す必要があります。 大きなプログラムを使って処理を行う場合、 関係しあっているたくさんのクラスを適切に制御しなくてはいけません。 その処理を行うための「窓口」を用意しておくと、 個別にたくさんのクラスを制御しなくても、「窓口」に対して、要求するだけですみます。

Facadeパターンは、既存のクラスを複数組み合わせて使う手順を、「窓口」となるクラスを作ってシンプルに利用できるようにするパターンです。

ちなみに、facadeとはフランス語を語源とする単語で「建物の正面」という意味です。発音するときはファサードの「サ」にアクセントを置きます。

「窓口」というと大仰な感じがしますが、詰まるところ「複数の処理を束ねた関数・メソッド」を用意するということです。

例題

以下のようにドキュメント作成を行う処理を想定します。
まずタイトル等を表示するヘッダ部、本文を記載するヘッダ部、末尾のフッタ部の三部構成です。

type User = {
    name: string;
}

class UserDB {
    // ユーザIDからユーザ情報を取得する
    static fetchUser = (userId: string): User => {
        // 本来はDBに問い合わせるが簡単のため固定データを返す
        return { name: 'てすと次郎' };
    }
}

class HeaderBuilder {
    // タイトルと著者名を出力する
    static write = (title: string, author: string) => {
        console.log(`題名:${title}`);
        console.log(`著者:${author}`);
    }
}

class BodyBuilder {
    // セクションを順番に出力する
    static write = (sections: string[]) => {
        sections.forEach(s => console.log(s + '\n'));
    }
}

class FooterBuilder {
    // 末尾に更新日時を出力する
    static write = () => {
        const current : Date = new Date();
        console.log(`更新日時:${current.toString()}`);
    }
}

// ユーザ情報を取得
const user: User = UserDB.fetchUser('100');
// ヘッダを記載
HeaderBuilder.write('今さら聞けないファサードパターン', user.name);
// 本文を記載
BodyBuilder.write([
    'ファサードパターンとは・・・', 
    '例として挙げられるのは・・・',
    '続いて実際のコードを見ていきましょう・・・',
    /** 以下略  */
]);
// フッタを記載
FooterBuilder.write();

出力

題名:今さら聞けないファサードパターン
著者:てすと次郎
ファサードパターンとは・・・

例として挙げられるのは・・・

続いて実際のコードを見ていきましょう・・・

更新日時:Fri Nov 13 2020 08:29:26 GMT+0900 (GMT+09:00)

「ドキュメントを作成する」という処理を行うために様々なクラスが登場しています。
実際にアプリケーションを開発する際には考慮しないといけないことが増えていくため、もっと大量のクラスを扱う必要があります。

ファサードパターンで実装

このとき「ドキュメントを作成する」という処理の窓口になってくれる処理を1つ作成すると非常に便利です。
それが「ファサードパターン」になります。

// ドキュメントを作成処理
class DocumentBuilder {
    static write = (userId: string, title: string, body: string[]) => {
        // ユーザ情報を取得
        const user: User = UserDB.fetchUser(userId);
        // ヘッダを記載
        HeaderBuilder.write(title, user.name);
        // 本文を記載
        BodyBuilder.write(body);
        // フッタを記載
        FooterBuilder.write();
    }
}

DocumentBuilder.write(
    '100', 
    '今さら聞けないファサードパターン', 
    [
        'ファサードパターンとは・・・', 
        '例として挙げられるのは・・・',
        '続いて実際のコードを見ていきましょう・・・'
    ]
);

呼び出し側は個別の処理を意識せず、DocumentBuilderという窓口だけを意識すればよいため取り回しも効きやすいです。

まとめ

今回はTypescriptでデザインパターンの一つである Facade Pattern について紹介しました。
冒頭でも述べたとおり、このパターンは知らず知らずのうちに使っていることが多いです。
なぜなら「一連の決まった処理」がコード上に何回も登場する場合、冗長な記載を避けるためにそれらをラップした関数(ファサード)を自然に作るためです。
数あるデザインパターンの中でも直感的で分かりやすいです。

メリットとしては 「呼び出し側に制御を記載することがないのでバグを減らす」 ことができたり 「窓口を設けることで外部と疎結合になる」 といった点があるかなと思います。