どの契約(契約による設計)の方が良いですか?
-
03-07-2019 - |
質問
メソッドがあるとします
public Patient(int id)
{
----
}
IDを指定してPatientオブジェクトを返します。2つの方法で契約を定義できます
- 患者が存在しない場合、メソッドはnullを返します
- 患者が存在しない場合、メソッドは例外をスローします。この場合、患者がデータベースに存在する場合はtrueを返し、そうでない場合はfalseを返すクエリメソッドも定義します...
どの契約を使用すべきですか?他の提案はありますか?
更新:このケースについてもコメントしてください... Idが割り当てられたデータベースではなく、ユーザーがUIで入力したものである場合(SSNなど)。
有効だと思うスティーブのヌルパターンについてのコメント: IDが存在しなかったことをすぐに知ることは本当に役立つので、ここではおそらく良い考えではありません。
また、ここでのヌルパターンはやや重いと思います
IDが悪いため例外をスローすることについてのRob Wellsのコメント: 患者の名前のタイプミスは例外的な状況だとは思わない」私見
解決
「有線で」ということを覚えておいてください。他の層(データベースまたはアプリケーションサーバー)は、実行できる最も高価なアクティビティの1つです。通常、ネットワークコールは、インメモリコールよりも数桁長くかかります。
したがって、冗長な呼び出しを避けるためにAPIを構造化することは価値があります。
APIが次のような場合、検討してください:
// Check to see if a given patient exists
public bool PatientExists(int id);
// Load the specified patient; throws exception if not found
public Patient GetPatient(int id);
その後、データベースに2回アクセスするか、これを回避するために適切なキャッシュに依存する可能性があります。
別の考慮事項: id、他の場所ではありません。各場所には、例外をスローするかどうかについて異なるポリシーが必要です。
これは私が過去に良い効果をもたらしてきたパターンです-2つの方法があります:
// Load the specified patient; throws exception if not found
public Patient GetExistingPatient(int id);
// Search for the specified patient; returns null if not found
public Patient FindPatient(int id);
明らかに、FindPatient()を呼び出すことでGetExistingPatient()を構築できます。
これにより、呼び出し元のコードが適切な動作を取得し、何か問題が発生した場合に例外をスローし、必要でない場合の例外処理を回避できます。
他のヒント
別のオプションは、ヌルオブジェクトパターンです。
おそらく例外をスローする必要があります。有効な患者を指していない id
がある場合、それはどこから来たのですか?非常に悪いことが起こった可能性があります。これは例外的な状況です。
編集:テキストに基づく検索など、整数ベースの検索以外の操作を行う場合、 null
を返すのは問題ありません。特にその場合、複数の結果(同じ名前、生年月日、またはあなたの基準が何でもある複数の患者)を返す可能性があるためです。
検索機能には、検索機能とは異なるコントラクトが必要です。
依存:
通常の操作でDB内のファイルと一致しないページ番号が発生する場合、空の(NULL)レコードが返されます。
ただし、特定のIDが常にレコードにヒットすることが予想される場合、レコードが見つからない場合(まれなはずですが)、例外を使用します。
DB接続エラーなどのその他のものは例外を生成するはずです。
通常の状況下で予想されるように、DBへのクエリは常に機能します(ただし、0レコードを返すかどうかは異なります)。
PS。ポインターを返しません。 (ポインタを所有しているのは誰ですか?)
レコードを持っている場合と持っていない場合があるオブジェクトを返します。ただし、レコードの存在を確認できます。潜在的にスマートポインターまたはコテキストを理解するスマートポインターよりも少しスマートなもの。
この状況では、存在しない患者に対してnullを返すメソッドが必要になります。
システム自体に問題がある場合、例外を使用して深刻な劣化を支援する傾向があります。
この場合、おそらくmosdtです:
- 検索フォームに入力された場合、患者のIDの入力ミス
- データ入力エラー、または
- 患者の記録がまだ入力されていないというワークフローの問題。
したがって、例外ではなくnullを返します。
データベースへの接続に問題がある場合、メソッドに例外を発生させます。
編集:署名の患者IDが整数であることがわかりました。StevenLoweに感謝します。そのため、理由のリストを修正しました。
例外を使用するタイミング(システムエラーの場合)と他のエラーを返す方法(単純なデータ入力のタイポの場合)を区別することについての私の基本的なポイントは、依然として有効です。私見。
HTH
歓声、
ロブ
このような単純な状況では、1。で十分すぎるようです。クライアントがnullを返した理由を知るために呼び出すコールバックメソッドのようなものを実装することができます。ただの提案。
説明を額面通りに取る場合、おそらく両方が必要です:
- 不正なIDはエラー/例外です。Adamが指摘しましたが、
- 消えたかもしれない他の場所にIDが与えられた場合、それらをチェックするためのクエリメソッドが必要になります
それを正しく読んだと仮定すると... Patient(100)を呼び出すと、IDが100の患者のオブジェクト参照が返されます。 idが100の患者が存在しない場合、nullを返すと思います。例外はIMOを過度に使用しているため、このケースはそれを要求しません。関数は単にnullを返しました。アプリケーションをクラッシュさせる可能性のあるエラーケースは作成しませんでした(もちろん、そのnullを処理せずにアプリケーションの他の部分に渡した場合を除きます)。
特にユーザーが特定のIDを持つ患者を検索する検索の一部であり、オブジェクト参照がnullになった場合は、単にnullを返すようにしますそのIDを持つ患者は存在しません。
例外をスローします。
nullを返す場合、次のようなコード:
Console.WriteLine(Patient(id).Name);
idが存在しない場合、NullReferenceExceptionで失敗します。これは、PatientNotFoundException(id)ほど有用ではありません。この例では、比較的簡単に追跡できますが、次の点を考慮してください。
somePatient = Patient(id)
// much later, in a different function:
Console.WriteLine(somePatient);
患者が存在するかどうかをチェックする関数の追加について:これは、PatientNotFoundExceptionsを完全に妨げないことに注意してください。例:
if (PatientExists(id))
Console.WriteLine(Patient(id).Name);
-別のスレッドまたは別のプロセスは、PatientExistsとPatientの呼び出しの間に患者を削除できます。また、これは1つではなく2つのデータベースクエリを意味します。通常、呼び出しを試行し、例外を処理することをお勧めします。
複数の値を返すクエリでは状況が異なります。リストとして;ここで、一致するものがない場合は空のリストを返すのが適切です。