よく使うJavaライブラリで味わうデザインパターン - Factoryパターン

普段よく使うJavaライブラリにも、デザインパターンが隠されています。日々の作業が忙しく見逃しがちですが、たまにはじっくり一種の芸術ともいえる美しい設計を味わってみましょう。


## 今回の芸術

```java
import java.net.URL;
import java.net.URLConnection;
...

URL url = new URL("http:で始まる文字列");
URLConnection connection = url.openConnection();
```

引数で指定したURLに接続するオブジェクトを生成するシーンですが、あらためて鑑賞してみると、神秘的なインターフェイスに見入ってしまいます。


## 鑑賞のポイント

[URLConnection](https://docs.oracle.com/javase/jp/8/docs/api/java/net/URLConnection.html)インスタンスを生成するために、`new URLConnection(url);` とするのではなく、わざわざ[URL](https://docs.oracle.com/javase/jp/8/docs/api/java/net/URL.html)クラスを介しています。しかし、それでもプログラマーに違和感を持たせないシンプルさに美しさを感じます。設計者の想いを探ってみましょう。


## Factoryパターンを使わない場合

それではまず、最も直感的なコードで、HTTPで接続するためのオブジェクトを生成してみましょう。

```java
// 注意: コンストラクタがprotectedなので実際はこのようには書けない
URLConnection connection = new HttpURLConnection(url);
```

接続方法にHTTPしか想定していない場合は、この方法で問題ないと思います。しかし、今後、HTTP以外のXXXプロトコルでも接続する必要が出てきた場合、`HttpURLConnection`と`XXXURLConnection`の**どちらかを意識して書き分ける必要**が出てきます。

```java
URLConnection connection = new HttpURLConnection(url);
```

とか、

```java
URLConnection connection = new XXXURLConnection(url);
```

というような、複数種類のインスタンス生成コードがプロジェクトのいろいろな個所に書かれることになります。

また、もし使用するクラスを`HttpURLConnection`から`XXXURLConnection`に統一することになった場合、**すべての該当するコードを修正**しなくてはいけません。これは美しくありませんね。

実は実際に、`URLConnection`のサブクラスには、`JarURLConnection`というものもあります。（このクラスはローカル上のjarファイルにアクセスすることを想定しています[^1]。）


## Factoryパターンを使った場合

冒頭のコードでは、Factoryパターンが使われています。

`URL`のコンストラクタにhttp:で始まる文字列をセットした場合は、`url.openConnection();` で、`HttpURLConnection`クラスのインスタンスが返ります。

```java
URL url = new URL("http:で始まる文字列"); // Factoryクラス
HttpURLConnection connection = (HttpURLConnection)url.openConnection(); // HttpURLConnectionにキャストできる
```

そして、jar:で始まる文字列をセットした場合は、`JarURLConnection`クラスのインスタンスが返ります。

```java
URL url = new URL("jar:で始まる文字列"); // Factoryクラス
JarURLConnection connection = (JarURLConnection)url.openConnection(); // JarURLConnectionにキャストできる
```

Factoryパターンを使えば、**どのクラスのインスタンスを生成するかをFactoryクラスに任せることができる**のです。さらに、**インスタンスをnewするコードは隠蔽される**ため、同じインターフェイスのまま、内部の実装を変更することもできます。なんてエレガントなのでしょう！


## Factoryパターンへの専門家のコメント

多くの専門家からも、Factoryパターンを評価するコメントが寄せられています。

Yoshihara Hidehikoさん

>  オブジェクトの使用者はファクトリに生成を依頼するだけで、オブジェクトの生成手順や種類を意識する必要はなく、望むオブジェクトを使用できる状態で手に入れることができます。
　もし生成するクラスの種類や作成手順が変更されても、ファクトリの中を手直しするだけですみます。

> [サルでもわかる 逆引きデザインパターン](http://www.nulab.co.jp/designPatterns/designPatterns2/designPatterns2-2.html) より


Alan Shalloway / James R. Trottさん

> オブジェクトの生成と管理を検討する段階で従うべき一般的な規則があります。それは、「オブジェクトは、他のオブジェクトの生成および/あるいは管理するか、他のオブジェクトを使用するかのどちらかのみを行い、双方を行ってはならない」というものです。

> [『デザインパターンとともに学ぶオブジェクト指向のこころ』](https://www.amazon.co.jp/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A8%E3%81%A8%E3%82%82%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E3%81%93%E3%81%93%E3%82%8D-Software-patterns-%E3%82%A2%E3%83%A9%E3%83%B3-%E3%82%B7%E3%83%A3%E3%83%AD%E3%82%A6%E3%82%A7%E3%82%A4/dp/4894716844/) より


## GoFのFactory Methodパターンとの違い

GoFのデザインパターンでは、Factoryパターンではなく、Factory Methodパターンが紹介されています。Factory Methodパターンでは、Factoryクラス（今回の場合はURLクラス）が抽象クラスとなり、その具象クラスであるXXXFactoryクラス（今回の場合はHttpURL/JarURLクラス[^2]）が、対応するインスタンス（今回の場合はHttpURLConnection/JarURLConnection）を作成することになります。

もし今後、`XXXURLConnection`のような`URLConnection`の派生クラスが増える可能性が高いなら、`URL`を抽象クラスにして、`XXXURL`のようなFactoryクラスを作れるようにした方がいいかと思います。しかし、設計者はその可能性は低いと考えたのでしょう。現状の設計の方がシンプルなので、使用者にとっては使いやすいのです。


## 最後に

わざわざ美術館に行かなくても、たった数行のコードを眺めるだけで知的な愉しみを味わうことができるのは、プログラマーの醍醐味でしょう。

Factoryパターンの芸術性に共感してくださったエンジニアの方は、ぜひ当社（[クオリサイトテクノロジーズ株式会社](http://www.qualysite.co.jp/)）の採用担当までご連絡ください！


## 関連記事
#### インスタンスを作る
- よく使うJavaライブラリで味わうデザインパターン - Factoryパターン
- [よく使うJavaライブラリで味わうデザインパターン - Builderパターン](http://qiita.com/takuya-s/items/3c3415962a7568c637ed)
- [よく使うJavaライブラリで味わうデザインパターン - Abstract Factoryパターン](http://qiita.com/takuya-s/items/6b26410d8eb47a9410e4)

#### インターフェイスをシンプルにする
- [よく使うJavaライブラリで味わうデザインパターン - Facadeパターン](http://qiita.com/takuya-s/items/eb663424a21094303b95)
- [よく使うJavaライブラリで味わうデザインパターン - Adapterパターン](http://qiita.com/takuya-s/items/45176b2bfc9fe07a9ce7)

#### 他のクラスに任せる
- [よく使うJavaライブラリで味わうデザインパターン - Template Methodパターン](http://qiita.com/takuya-s/items/8898e9bae34acada6480)
- [よく使うJavaライブラリで味わうデザインパターン - Strategyパターン](http://qiita.com/takuya-s/items/473699b5cb2d5329eed3)


## 参考URL
- [Javaでクラスからそのクラスが入ってるJarを取得する方法](http://d.hatena.ne.jp/twisted0517/20070419/1176968815)
- [Jarファイルメモ(Hishidama's java-archive Memo)](http://www.ne.jp/asahi/hishidama/home/tech/java/jar.htm)



[^1]: JarURLConnectionクラスの使い方の例は、参考URLをご覧ください。
[^2]: 実際には存在しません。