マニュアル: ファクトリ

投稿日:

どのパターンを使うべきか

  • 引数が不要な場合→コンストラクタ
    • Strategyを選ぶときなど。
  • 順番に構築する必要がある→Builderを作る
    • 例: SQLを構築するビルダ
  • それ以外→まずFactory Methodを作る
    • その中でBuilderの方が良いと思ったら、Builderに作り変える。

ものすごく単純化していますが、基本的にはこれでいいと思います。

理由

まず、「順番に構築する必要がある」場合は、 Builderで対応する必要があります。 こちらは説明不要だと思うので省きます。

Factory Methodにすると引数が多くなってしまう場合

この場合にまず考えるべきことは、 「引数をValue Objectにできないか」です。 例えば、公開鍵でSFTP接続したいときに以下の引数を渡す場合を考えます。

  1. 接続先ホスト名
  2. 接続先ポート番号
  3. 接続先ユーザ
  4. 秘密鍵
  5. 秘密鍵パスフレーズ
  6. known_hosts

単純に実装すると、Stringが5つ、intが1つ並んだ、以下のようなメソッドができます。 (コンストラクタでも同じ)

Sftp sftp = Sftp.of(host, port, user, privateKeyPath, passPhrase, knownHostsPath);

しかし、1と2、4と5はひとまとまりに考えることができます。

PrivateKey privateKey = PrivateKey.of(privateKeyPath, passPhrase);
Server server = Server.of(host, port);

Sftp sftp = Sftp.of(server, user, privateKey, knownHosts);

さらに、privateKeyとuserを「認証情報」としてひとまとまり、 serverとknownHostsを「接続先情報」としてひとまとまりにすると、 以下のようにできます。

PrivateKey privateKey = PrivateKey.of(privateKeyPath, passPhrase);
Server server = Server.of(host, port);

AuthInfo authInfo = AuthInfo.of(user, privateKey);
SshServer sshServer = SshServer.of(server, knownHosts);

Sftp sftp = Sftp.of(sshServer, authInfo);

引数がたった2つになりました。 しかも、このPrivateKey, Server, AuthInfo, SshServerは他でも 使える可能性が高いクラスです。 AuthInfoのファクトリーメソッドの引数を変えるだけで、 パスワード認証にも対応可能です。

オプショナルな引数が多い場合

これは2つのパターンがあります。

  • デフォルト値がだいたい決まっている
  • オプショナル項目そのものが多い

後者については、Builderパターンが適している場合もあります。 前者の場合は、引数の省略で対応できる場合が多いです。 先程のSftpクラスだと、通常は、ポート22を使います。 したがって、以下のようにかけます。

Sftp sftp = Sftp.of(host, user, privateKeyPath, passPhrase, knownHostsPath);

Value Objectを使うと、以下のように書けます。 引数が多いと組み合わせが爆発しますが、 Value Objectを使っているため、ほとんど影響がありません。

PrivateKey privateKey = PrivateKey.of(privateKeyPath, passPhrase);
Server server = Server.of(host); // 違うのはここだけ

AuthInfo authInfo = AuthInfo.of(user, privateKey);
SshServer sshServer = SshServer.of(server, knownHosts);

Sftp sftp = Sftp.of(sshServer, authInfo);

最初から完璧さを求めない

これでは不十分で、もっと複雑なパターンを使う必要があるかもしれません。 ただ、それはいつになるのかは分かりません。いわゆるYAGNIの法則です。 必要になったときだけ、追加するので十分だと思います。