web-dev-qa-db-ja.com

コンストラクターまたはサービスのパラメーターの確認

私は this SOページを読んで、オブジェクトを構築するときにパラメーターをいつチェックするかについてのページを読んでいました。受け入れられた答えは、無効なオブジェクトが建設。

私はそのアプローチに同意し、Personなしでnameを構築する方法はわかりません。

ただし、 comments のいずれかが推奨されます:

また、2番目のオプションは、1番目のオプションよりも再利用可能であるため、より優れていることに同意します。最初のオプションは、オブジェクト指向の原則に違反しています。ファクトリーメソッドでさえ、それよりもよく設計されています。

質問:

  1. OOPの原則に違反しているのは、コンストラクターで例外をスローしたときですか?コンストラクターが機能してはいけないというガイドラインですか?

  2. OPによって提案された他のアプローチはPersonServiceでしたが、これは単なる推測にすぎませんが、このアプローチでは、クライアントコードがpublic void addPerson(Person personToAdd)を呼び出して人物オブジェクトがnullを含まない?彼らがそのチェックを回避する方法を見つけたらどうなりますか?または、public void addPerson(Person personToAdd)の前に、有効なPersonオブジェクトを期待する、自分が記述し​​ていない別のクラスでそのオブジェクトを使用しますか?

繰り返しになりますが、これはすべて推測の一部ですが、Personオブジェクトが作成時に行われたはずのときに有効であることを保証するのは、クライアントに大きな責任を負っているようです。

4
user315575

1)いいえOOP exception をスローすると原理が壊れます- コンストラクタ

Bjarne Stroustrupは彼の著書で、IBMやSunのような複数の企業の専門家と協力して、例外が1984年から1989年の間に言語にどのように設計されたかC++の設計と進化を思い出しました:

一部の人にとって、例外の最も重要な側面の1つは、コンストラクターで検出されたエラーを報告するための一般的なメカニズムを提供することです。

これは、Javaおよびその他のOO言語についても同様です。

2)サービスを使用してオブジェクトを作成することも有効な方法です。ビルダーやファクトリを使用してオブジェクトを作成することは珍しくありません。

ファクトリを使用すると、例外をスローするのとは異なる方法でエラーを管理でき、特に、構築前にパラメータの一貫性を制御できます。

ただし、この種のサービスをコンストラクタの上で使用することが常に望ましいとは限りません。

さらに、すべてのエラーを予測することは不可能です。作成中に、パラメーターに関連しない予期しないイベントが発生したとします。たとえば、大きなオブジェクトを作成するのに十分なメモリが残っていない、または一部のリソースがチェックされたが割り当てられなかった(特にRAIIコンテキストで)。

3)それにもかかわらず、例外を悪用しないでください

例外はパラメーター検証の代わりにはなりません。例外に関する最も重要な原則は、例外的な状況でのみ発火することです。悪いパラメーターが一般的な状況である場合、または3つのうちの1つの構造が例外を引き起こす可能性があると予想される場合は、設計に本当に疑問を投げかけ、リスクを減らすためにそれをリファクタリングする必要があります。

名前を事前にチェックする必要があると想定して防御的プログラミングに使用する場合、この例外をセーフティネットとして提供すれば、問題ありません。

1
Christophe
  1. スローされた例外はオブジェクトの内部構造を公開するため、違反が確認できる唯一の原則はカプセル化です。オブジェクトが公開されていない場合、これは問題にはなりません。歴史的に、オブジェクトが構築の途中で失敗した場合、そのポイントに割り当てられたすべてのリソースをクリーンアップする必要があるかもしれません。ガベージコレクターはこの影響を最小限に抑えました(ただし排除はしていません)。また、コンストラクタを呼び出すと、コードがコンストラクタの署名に明示的に結合されます。これはほとんど取るに足らないことですが、依存関係の新しいバージョンに移行するときに発生する可能性があるように、シグネチャが変更された場合は再作業が必要になる場合があります。
  2. えっ?これは私にはあまり意味がありません。

オブジェクトをきれいに構築するために現在好まれているパターン(IMO)は Builderパターン です。 Builderの利点の1つは、コンストラクターに渡される前にパラメーターを検証できることです。この検証は、特定のパラメータが設定されている場合、またはbuild()の呼び出し中に発生する可能性があります。 param()呼び出しでの検証は Circuit Breaker として機能し、高速に失敗し、使用前に他のパラメーター値を取得する作業を排除する可能性があります。例。

_...size(5).foo(getMassivelyComplexObject()).build
_

_5_が有効なsizeではなく、検証がsize()呼び出しで実装されている場合、foo()の値を取得するために必要な作業は回避できました。

コンストラクタのシグネチャが変更された場合、ビルダーは次の2つの方法でユーザーを隔離します。

  1. Builder param()の呼び出しは通常、順序に依存しません。
  2. Builderが特定のパラメータのデフォルト値を提供する場合、個々のBuilder param()呼び出しはオプションです。

Builderパターンには他にも多くの優れた点がありますが、質問は建設中の失敗に関するものなので、ここで終了します。

0
WillD