普段よく使うJavaライブラリにも、デザインパターンが隠されています。日々の作業が忙しく見逃しがちですが、たまにはじっくり一種の芸術ともいえる美しい設計を味わってみましょう。
今回の芸術
import java.net.URL;
import java.net.URLConnection;
...
URL url = new URL("http:で始まる文字列");
URLConnection connection = url.openConnection();
引数で指定したURLに接続するオブジェクトを生成するシーンですが、あらためて鑑賞してみると、神秘的なインターフェイスに見入ってしまいます。
鑑賞のポイント
URLConnectionインスタンスを生成するために、new URLConnection(url);
とするのではなく、わざわざURLクラスを介しています。しかし、それでもプログラマーに違和感を持たせないシンプルさに美しさを感じます。設計者の想いを探ってみましょう。
Factoryパターンを使わない場合
それではまず、最も直感的なコードで、HTTPで接続するためのオブジェクトを生成してみましょう。
// 注意: コンストラクタがprotectedなので実際はこのようには書けない
URLConnection connection = new HttpURLConnection(url);
接続方法にHTTPしか想定していない場合は、この方法で問題ないと思います。しかし、今後、HTTP以外のXXXプロトコルでも接続する必要が出てきた場合、HttpURLConnection
とXXXURLConnection
のどちらかを意識して書き分ける必要が出てきます。
URLConnection connection = new HttpURLConnection(url);
とか、
URLConnection connection = new XXXURLConnection(url);
というような、複数種類のインスタンス生成コードがプロジェクトのいろいろな個所に書かれることになります。
また、もし使用するクラスをHttpURLConnection
からXXXURLConnection
に統一することになった場合、すべての該当するコードを修正しなくてはいけません。これは美しくありませんね。
実は実際に、URLConnection
のサブクラスには、JarURLConnection
というものもあります。(このクラスはローカル上のjarファイルにアクセスすることを想定しています1。)
Factoryパターンを使った場合
冒頭のコードでは、Factoryパターンが使われています。
URL
のコンストラクタにhttp:で始まる文字列をセットした場合は、url.openConnection();
で、HttpURLConnection
クラスのインスタンスが返ります。
URL url = new URL("http:で始まる文字列"); // Factoryクラス
HttpURLConnection connection = (HttpURLConnection)url.openConnection(); // HttpURLConnectionにキャストできる
そして、jar:で始まる文字列をセットした場合は、JarURLConnection
クラスのインスタンスが返ります。
URL url = new URL("jar:で始まる文字列"); // Factoryクラス
JarURLConnection connection = (JarURLConnection)url.openConnection(); // JarURLConnectionにキャストできる
Factoryパターンを使えば、どのクラスのインスタンスを生成するかをFactoryクラスに任せることができるのです。さらに、インスタンスをnewするコードは隠蔽されるため、同じインターフェイスのまま、内部の実装を変更することもできます。なんてエレガントなのでしょう!
Factoryパターンへの専門家のコメント
多くの専門家からも、Factoryパターンを評価するコメントが寄せられています。
Yoshihara Hidehikoさん
オブジェクトの使用者はファクトリに生成を依頼するだけで、オブジェクトの生成手順や種類を意識する必要はなく、望むオブジェクトを使用できる状態で手に入れることができます。
もし生成するクラスの種類や作成手順が変更されても、ファクトリの中を手直しするだけですみます。
Alan Shalloway / James R. Trottさん
オブジェクトの生成と管理を検討する段階で従うべき一般的な規則があります。それは、「オブジェクトは、他のオブジェクトの生成および/あるいは管理するか、他のオブジェクトを使用するかのどちらかのみを行い、双方を行ってはならない」というものです。
GoFのFactory Methodパターンとの違い
GoFのデザインパターンでは、Factoryパターンではなく、Factory Methodパターンが紹介されています。Factory Methodパターンでは、Factoryクラス(今回の場合はURLクラス)が抽象クラスとなり、その具象クラスであるXXXFactoryクラス(今回の場合はHttpURL/JarURLクラス2)が、対応するインスタンス(今回の場合はHttpURLConnection/JarURLConnection)を作成することになります。
もし今後、XXXURLConnection
のようなURLConnection
の派生クラスが増える可能性が高いなら、URL
を抽象クラスにして、XXXURL
のようなFactoryクラスを作れるようにした方がいいかと思います。しかし、設計者はその可能性は低いと考えたのでしょう。現状の設計の方がシンプルなので、使用者にとっては使いやすいのです。
最後に
わざわざ美術館に行かなくても、たった数行のコードを眺めるだけで知的な愉しみを味わうことができるのは、プログラマーの醍醐味でしょう。
Factoryパターンの芸術性に共感してくださったエンジニアの方は、ぜひ当社(クオリサイトテクノロジーズ株式会社)の採用担当までご連絡ください!
関連記事
インスタンスを作る
- よく使うJavaライブラリで味わうデザインパターン - Factoryパターン
- よく使うJavaライブラリで味わうデザインパターン - Builderパターン
- よく使うJavaライブラリで味わうデザインパターン - Abstract Factoryパターン