Java : Facade パターン (図解/デザインパターン)
Facade パターンとは、GoF によって定義されたデザインパターンの1つです。
複雑な操作が必要となるサブシステムに対して、シンプルなインタフェースを提供します。
本記事では、Facade パターンを Java のコード付きで解説していきます。
デザインパターン(GoF) 関連記事
- 生成に関するパターン
- 振る舞いに関するパターン
概要
Facade パターンとは、
- 複雑な操作や連携が必要となるクラス群 (サブシステム、モジュールなど) があり
- 上記に対して、使いやすいシンプルなインタフェースを提供する
という目的のための設計です。
もっと簡単にいうと、
- 複雑な処理をまとめる
ということです。
サブルーチン の考え方をもう少し広げた感じでしょうか。
Facade は、日本語的に発音すると「ファサード」となります。
意味は「建物の正面」ですね。
【Facade パターンのイメージ】
クライアントは とあるデータを出力 したいとします。
しかし、そのためには クラスA, B, C, D を使う必要があります。
例えば …
- クラスA で元となるデータを取得
- それを クラスB で変換
- さらに クラスC で加工
- 最後に クラスD で出力
という工程が必要だとしましょう。
欲しいのは、最後の結果だけ です。
しかし、そのためには クラスA, B, C, D の使い方をプログラマーが 理解する必要 があります。
1回だけしか使わない、自分だけしか使わない、というのであればそれもよいかもしれません。
しかし、そうでなけば手間ですし工数もかかります。
「ファサード」クラスは、クラスA, B, C, D をクライアントから 隠蔽(カプセル化) します。
クライアントは、「ファサード」クラスの シンプル なインタフェースを呼び出すだけです。
クラスA, B, C, D を知る必要はありません。それはコーディングの時間短縮にもつながるでしょう。
これが、Facade パターンのメリットになります。
オブジェクト指向に限らず、プログラミングにおいては、わりと自然な考え方なのかな … と思います。
関連記事:
クラス図とシーケンス図
上の図は、Facade パターンの一般的なクラス図とシーケンス図です。
依存関係は、
- Facade → ClassA, B, C
です。逆はない のでご注意ください。
それでは、このクラス図をそのままコードにしてみましょう。
まずは ClassA, B, C です。
- ClassA で値を取得
- ClassB で値を変換
- ClassC で値を出力
という流れになります。
public class ClassA {
public String getText() {
return "facade pattern!";
}
}
public class ClassB {
public String convert(String text) {
return text.toUpperCase();
}
}
public class ClassC {
public void print(String text) {
System.out.println(text);
}
}
次に、Facade クラスです。
public class Facade {
private final ClassA a = new ClassA();
private final ClassB b = new ClassB();
private final ClassC c = new ClassC();
public void operate() {
final var text1 = a.getText();
final var text2 = b.convert(text1);
c.print(text2);
}
}
それでは、これらのクラスを使ってみましょう。
といっても、Facade クラスのシンプルなメソッドを呼び出すだけです。
final var facade = new Facade();
facade.operate();
// 結果
// ↓
//FACADE PATTERN!
結果も問題なしですね。
"facade pattern!" という文字列が、大文字に変換されてからコンソールに出力されました。
具体的な例
もう少し具体的な例も見てみましょう。
Webページを表示するブラウザを考えてみます。
Webページを表示するためには、
- HTMLドキュメントの解析 (HtmlParser)
上記の解析結果 (HtmlItem) - 画像の読み込み (ImageReader)
- 動画の読み込み (VideoReader)
が最低限必要になるとしましょう。
あと、例を簡単にするために、画像と動画はそれぞれ1つしか読み込めないとします。
クライアントとしては、
- HTMLドキュメントの解析
- 画像・動画の読み込み
といった細かいことには興味がありません。
とにかく「Webページ」を 表示したいだけ です。
それでは Facade パターンを使ってコードを書いてみましょう。
HtmlParser クラスは、HTMLドキュメントを解析して HtmlItem オブジェクトを生成します。
(HtmlItem は「レコードクラス」です)
public class HtmlParser {
public HtmlItem parse(String html) {
... 解析処理は省略 ...
return new HtmlItem(... 省略 ...);
}
}
public record HtmlItem(String text, String image, String video) {
}
ImageReader クラスは画像を読み込みます。
ここでは、実際の読み込み処理ではなく、代わりにテキストを表示させます。
public class ImageReader {
public void read(String image) {
System.out.println("画像読み込み OK : " + image);
}
}
VideoReader クラスは動画を読み込みます。
こちらも、実際の読み込み処理ではなく、代わりにテキストを表示させます。
public class VideoReader {
public void read(String video) {
System.out.println("動画読み込み OK : " + video);
}
}
最後に WebPageFacade クラスです。
今までのクラスを使って、Webページを表示させます。
(といっても、非常に簡易的なテキストでの表示です)
public class WebPageFacade {
public void show(String html) {
System.out.println("-- WebPage show --");
final var parser = new HtmlParser();
final var item = parser.parse(html);
final var imageReader = new ImageReader();
imageReader.read(item.image());
final var videoReader = new VideoReader();
videoReader.read(item.video());
System.out.println("テキスト : " + item.text());
}
}
それでは、実際に WebPageFacade クラスを使ってみましょう。
show メソッドに HTMLドキュメントを指定します。
final var html = """
<html>
<body>
<img src="image.jpg"></img>
<video controls src="video.mp4"></video>
Hello, World!
</body>
</html>
""";
final var facade = new WebPageFacade();
facade.show(html);
// 結果
// ↓
//-- WebPage show --
//画像読み込み OK : image.jpg
//動画読み込み OK : video.mp4
//テキスト : Hello, World!
テキストによる簡易的なものですが、無事に Webページが表示できました。
WebPageFacade を使うことにより、
- HtmlParser
- HtmlItem
- ImageReader
- VideoReader
といったクラスを意識しなくて済みます。
つまり、これらのクラスを 隠蔽(カプセル化) したわけですね。
まとめ
Facade パターンとは、
- 複雑な操作や連携が必要となるクラス群 (サブシステム、モジュールなど) があり
- 上記に対して、使いやすいシンプルなインタフェースを提供する
という目的のための設計です。
オブジェクト指向に限らず、プログラミングにおいては、わりと自然な考え方なのかな … と思います。
ぜひ有効に活用していきたいですね。
関連記事
- 標準APIにならう命名規則
- コメントが少なくて済むコードを目指そう
- シングルトン・パターンの乱用はやめよう
- メソッドのパラメータ(引数)は使う側でチェックしよう
- 不変オブジェクト(イミュータブル) とは
- 依存性の注入(DI)をもっと気軽に
- 不要になったコードはコメントアウトで残さずに削除しよう
- 簡易的な Builder パターン
- 読み取り専用(const) のインタフェースを作る
- 図解/デザインパターン一覧 (GoF)
- Abstract Factory パターン
- Adapter パターン
- Bridge パターン
- Builder パターン
- Chain of Responsibility パターン
- Command パターン
- Composite パターン
- Decorator パターン
- Factory Method パターン
- Flyweight パターン
- Interpreter パターン
- Iterator パターン
- Mediator パターン
- Memento パターン
- Observer パターン
- Prototype パターン
- Proxy パターン
- Singleton パターン
- State パターン
- Strategy パターン
- Template Method パターン
- Visitor パターン