はじめに
本記事は、デザインパターン学習中の私が学習中に詰まったポイント、間違えてしまったポイントをもとに学んだことを書いたものです。
個人の理解に基づいておりますため、間違いがあれば教えていただけると幸いです。
★9ヶ月前くらいにデザインパターンの勉強のために執筆し、社内で公開していた記事をこちらにも投稿したものとなります。
「これ、どっちのパターンなんだろう?」
Proxyパターンを学習していたときのことです。
私はサンプル実装として、以下のようなコードを作成しました。
このとき、キャッシュの画像を表示するサービスのクラスをProxy(代理人)クラスとし、フォルダから読み込んだ画像を表示するクラスをRealSubject(主体)クラスとしています。
キャッシュにすでに読み込まれた画像があるときはProxyが処理を肩代わりし、キャッシュにない画像を指定されたときに初めてRealSubjectが画像読み込み処理を行う、ということで、Proxyパターンには当てはまっているように思えます。
しかし見方を変えると、このプログラムは、画像のインスタンス(BitmapImage)を生成してキャッシュに登録し、可能な限り(キャッシュに存在する画像が呼ばれる限り)すでに作成したインスタンスを使って画像を表示する、というものになります。
あれ?それって、Flyweightパターンじゃない?
Proxyパターンで間違いはないはずだけど、うまく説明できないぞ?
整理してみる
Proxyパターンとは、オブジェクトの処理をオブジェクトの代わりに処理するクラス(Proxy)を用意することで、オブジェクトの 処理を分散することを目的としたパターンです。
たとえば、とあるインスタンスの生成処理が重い場合に、インスタンスに設定する値を取得する等の、インスタンス自体が存在しなくても行える軽い処理をProxyクラスに任せます。そのうえで本当にインスタンスが必要になったときにはじめてインスタンス生成処理を行うことで、重い処理の実行を本当に必要なタイミングまで遅延させることが可能です。
Flyweightパターンとは、すでに生成したインスタンスを要求された場合に新しく作らず、すでにあるインスタンスを返すことで同じインスタンスを再利用し、 処理を軽くする ことを目的とするパターンです。作ってあるインスタンスを返すということでSingletonパターンっぽいな?とも思えますが、Singletonパターンとは違い、「1つのクラスについてインスタンスが1つだけ」という決まりはありません。
結局間違っていたのか
私が作成したプログラムは、
「キャッシュにない画像が呼ばれるまで画像の読み込み処理を遅延させる」
という部分がProxyパターン、
「画像のインスタンスをキャッシュに保持して再利用する」
という部分がFlyweightパターンに当てはまっていました。見方によってはどちらのパターンとして見ることもできるものになっていたんですね。
デザインパターンとは、クラス・ライブラリの設計においてしばしば直面する問題に対処する設計をまとめたものです。どのような問題を解決したいかによって、適用できるパターンは変わります。
今回、(Proxyパターンの学習用の試作ではありますが、)解決したかった問題は「『画像をフォルダから読み込んで表示する』処理を、本当に必要な時にだけ行いたい」という問題でした。
そこで、「読み込んだ画像をキャッシュに保持しておき、既に一度読み込んだ画像が呼び出されたときにフォルダから画像を読み込むクラスの『代わりに』キャッシュの画像を表示する」クラスを作成しました。
Proxyパターンのメリットである「オブジェクトの処理を分散できる」ことを利用して問題を解決できています。
そのうえで、Proxyクラスにさせたい処理である「キャッシュの画像を再利用する」部分をFlyweightパターンで実現していたんですね。
まとめ
複数のデザインパターンを無意識に活用していたことで混乱してしましたが、各デザインパターンについて、「どういう設計の問題を解決できるパターンなのか」を理解する必要があると改めて思いました。
「ここは○○パターンでクラス間の依存が切れる!」とか、言えるようになりたいです。
◆◆◆
最後まで読んでいただき、ありがとうございました。
以下は前回のデザインパターンの記事です。よければ合わせてどうぞ。
【デザインパターン】悪戦苦闘!デザインパターン ~State・Strategy編~