本章では、Facade(ファサード)パターンの基本的な考え方を、サブシステムが複雑になっていく状況を題材に解説します。実際のライブコーディングは行わず、1枚のスライド図が徐々に変化していく形式のレクチャーです。
Facadeが無い場合の問題
例えば、次の図のようなサブシステムがあったとします。クラスがいくつも存在しており、パッと見ただけでは複雑なサブシステムだという印象を受けます。
図1 クライアントが複数のサブシステムクラスを直接呼び出している状態
このサブシステムをどう使えばいいのか、外から見てもよく分かりません。中にはクラスの呼び出し順が決まっているものもあり、「このクラスを生成してから、こうやって、こうやって」といった手順を利用者側が把握しておく必要が出てきます。
図2 Fan・Power・Box・Cameraの間で呼び出し順が決まっているケース
さらに、クラスの数が多いためどれを使えばよいのか分かりにくく、「このサブシステムのフル機能は結局いくつあるのか」を把握することも難しくなります。クライアント(View)側から見ると、サブシステム全体を理解しない限り安心して使うことができません。
図3 サブシステム全体を理解しないと使い方が把握できない状態
Facadeを導入する
そこで、サブシステムの一番の窓口となる場所に、ファサードオブジェクトを1つ置きます。クライアントはサブシステムの個々のクラスを直接呼び出すのではなく、このFacadeを経由して呼び出すようにします。
図4 クライアントとサブシステムの間にFacadeを1つ配置した状態
サブシステムの機能をまとめて公開する
サブシステムのクラス群の使い方は、すべてこのFacadeでまとめて公開します。仮にサブシステムに機能が14個あったとしたら、Facadeはメソッドを14個公開し、「1個ずつこうやって使うんだよ」という形で機能を提示していくイメージです。
図5 サブシステムの14個の機能をFacadeがまとめて公開する
これは、そのサブシステムでできることのリストアップをしているとも言えます。フル機能が何かも分かりますし、クライアント側も「こういう機能が14種類あるんだな、じゃあこれとこれを使おう」という形で、必要なものを選んで呼ぶだけで済むようになります。
クライアントはFacadeを呼ぶだけでよい
何より、クライアントはサブシステムのクラス群そのものを理解する必要がなくなり、Facadeだけを理解すればよくなる点が大きなメリットです。呼び出し順が決まっているものについても、Facadeのメソッドの中でその手順を吸収してあげれば、「全員がFacadeを呼ぶ」というルールにしておくだけで手順が統一されます。
図6 クライアントはFacade経由で機能を呼び出すだけでよい
このため、クライアントコードはFacadeに対してドットを打てば、IntelliSenseで使えるものがずらっと一覧表示されるので、その中から必要なものを1つ選ぶだけでコーディングができるようになります。
図7 MachineFacadeに対してドットを打つとIntelliSenseで公開メソッドが一覧表示される
参考コード:Facadeの有無による違い
動画中では実際のコードは映りませんが、図とIntelliSenseの一覧(BacklightOff/BoxExternalTemperature/BoxInternalTemperature/CameraTake/FanGetData/PowerOff/PowerOnなど)から読み取れる構成をもとに、参考コードとして整理します。
Facadeが無い場合、クライアントはFan・Power・Box・Cameraなど、サブシステムの各クラスを直接インスタンス化し、呼び出し順にも注意しながら操作する必要があります。
// サブシステムのクラス群(Facadeが無い場合)
public class Fan
{
public FanEntity GetData() { /* ... */ return new FanEntity(); }
}
public class FanEntity { /* Fanから取得するデータ */ }
public class Power
{
public void On() { /* ... */ }
public void Off() { /* ... */ }
}
public class Box
{
public double InternalTemperature => /* ... */ 0;
public double ExternalTemperature => /* ... */ 0;
public void BacklightOff() { /* ... */ }
}
public class Camera
{
public void Take() { /* ... */ }
}
この状態では、クライアント(View)側のコードにサブシステムの詳細がそのまま現れます。
// クライアント側(Facadeが無い場合) var power = new Power(); power.On(); // ① まず電源を入れる var fan = new Fan(); var fanData = fan.GetData(); // ② Fanのデータを取得 var box = new Box(); var inTemp = box.InternalTemperature; var outTemp = box.ExternalTemperature; var camera = new Camera(); camera.Take(); // ③ 撮影する power.Off(); // ④ 最後に電源を切る // → 4つのクラスと呼び出し順を、クライアント自身が把握する必要がある
これに対してFacadeを導入すると、サブシステムのクラス群はFacadeの内部に隠蔽され、クライアントはFacadeの公開メンバーだけを見ればよくなります。
// Facade(サブシステムの窓口となるクラス)
public class MachineFacade
{
private readonly Fan _fan = new();
private readonly Power _power = new();
private readonly Box _box = new();
private readonly Camera _camera = new();
public void PowerOn() => _power.On();
public void PowerOff() => _power.Off();
public FanEntity FanGetData() => _fan.GetData();
public double BoxInternalTemperature => _box.InternalTemperature;
public double BoxExternalTemperature => _box.ExternalTemperature;
public void BacklightOff() => _box.BacklightOff();
public void CameraTake() => _camera.Take();
// ...サブシステムの機能数(この例では14個)だけメソッド/プロパティを公開する
}
クライアント側は、Facadeの1つのインスタンスに対してメソッドを呼ぶだけになります。呼び出し順の制約がある場合も、その手順をFacade内部にまとめてしまえます。
// クライアント側(Facadeがある場合) var facade = new MachineFacade(); facade.PowerOn(); var fanData = facade.FanGetData(); var inTemp = facade.BoxInternalTemperature; facade.CameraTake(); facade.PowerOff(); // → クライアントはFacadeだけを見ればよく、 // Fan・Power・Box・Cameraそれぞれの存在や呼び出し順を意識しなくてよい
まとめ
サブシステムでできることをまとめて公開するクラス、これをFacade(ファサード)と呼びます。Facadeを導入することで、クライアントはサブシステムの内部構造や呼び出し順を意識せずに済み、Facadeという単一の窓口だけを理解すればよくなります。
図8 サブシステムの機能をまとめて公開するクラス=Facade
■非公開コース「C#14新機能」プレゼント:
非公開コース「C#14新機能」(80分)をご覧になりたい方は
こちらからURLとパスワードを発行していますので、ご覧になってみてください。
非公開コース「C#14新機能」を観る
参考にした書籍
実戦で役立つ C#プログラミングのイディオム/定石&パターン
プログラミングC# 第8版
オブジェクト指向
・アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技
すばらしい本です。オブジェクト指向が詰まっています。
・オブジェクト脳のつくり方―Java・UML・EJBをマスターするための究極の基礎講座
サンプルコードはjavaですが,最初にオブジェクト指向に目覚めるのに最適な本です。
・Head Firstオブジェクト指向分析設計 ―頭とからだで覚えるオブジェクト指向の基本
マンガみたいな感じで読めて,オブジェクト指向について学べます。
・Clean Code アジャイルソフトウェア達人の技
・Clean Architecture 達人に学ぶソフトウェアの構造と設計
・Adaptive Code ~ C#実践開発手法
・.NETのエンタープライズアプリケーションアーキテクチャ
・実装パターン
廃盤のため異常に高くなりすぎなので,様子を見た方がいい気がします。一万円のボリュームがあるかどうかは微妙です。
・オブジェクト指向でなぜつくるのか
・レガシーコード改善ガイド
・リファクタリング 既存のコードを安全に改善する
デザインパターン
・オブジェクト指向における再利用のためのデザインパターン
・オブジェクト指向のこころ
・Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本
ドメイン駆動開発
・エリック・エヴァンスのドメイン駆動設計
・実践ドメイン駆動設計
・ドメイン駆動
・現場で役立つシステム設計の原則
・エンタープライズアプリケーションアーキテクチャパターン