エラー変数はアンチパターンですか、それとも良い設計ですか?


44

実行を停止してはならないいくつかのエラーを処理するためにerror、クライアントがチェックして例外をスローするために使用できる変数があります。これは反パターンですか?これを処理するより良い方法はありますか?この動作の例については、PHPのmysqli APIをご覧ください。可視性の問題(アクセサ、パブリックスコープとプライベートスコープ、クラス内の変数はグローバルですか?)が正しく処理されると仮定します。


6
これは、どのようなtry/ catchのために存在します。また、あなたは置くことができますtry/ catch(懸念の大きい分離を可能にする)、それを処理するためのより適切な場所に多くの更なるアップスタックを。
jpmc26 14年

心に留めておくべきこと:例外ベースの処理を使用して例外を取得する場合、ユーザーに多くの情報を表示したくありません。ElmahやRaygun.ioなどのエラーハンドラを使用してインターセプトし、一般的なエラーメッセージをユーザーに表示します。スタックトレースや特定のエラーメッセージをユーザーに表示しないでください。ユーザーはアプリの内部動作に関する情報を開示するため、悪用される可能性があります。
Nzall

4
@Nateあなたのアドバイスは、ユーザーが完全に信頼されていないセキュリティ重視のアプリケーションにのみ適用されます。あいまいなエラーメッセージはそれ自体がアンチパターンです。ユーザーの明示的な同意なしにエラーレポートをネットワーク経由で送信することも同様です。
piedar 14年

3
:私はこれがより自由に議論することができます別の質問を作成@piedar programmers.stackexchange.com/questions/245255/...
Nzall

26
APIデザインの一般原則は、PHPが何をしているのかを常に確認し、次に正反対のことを行うことです。
フィリップ14年

回答:


65

言語が本質的に例外をサポートしている場合、例外をスローすることをお勧めします。クライアントは、例外を発生させたくない場合に例外をキャッチできます。実際、コードのクライアントは例外を予期しており、戻り値をチェックしないため、多くのバグに遭遇します。

選択肢がある場合、例外を使用することにはかなりの利点があります。

メッセージ

例外には、開発者がデバッグに使用したり、必要に応じてユーザーに表示したりできる、ユーザーが読み取り可能なエラーメッセージが含まれています。消費するコードが例外を処理できない場合、常にログに記録できるため、開発者は他のすべてのトレースで停止して戻り値が何であるかを把握し、テーブルにマッピングして何が何であるかを把握する必要がありません実際の例外。

戻り値では、追加情報を簡単に提供することはできません。一部の言語は、最後のエラーメッセージを取得するためのメソッド呼び出しをサポートするため、この懸念は少し緩和されますが、呼び出し元が追加の呼び出しを行う必要があり、時にはこの情報を運ぶ「特別なオブジェクト」へのアクセスが必要になります。

例外メッセージの場合、次のような可能な限り多くのコンテキストを提供します。

ユーザーのプロファイルで参照されているユーザー「bar」の名前「foo」のポリシーを取得できませんでした。

これを戻りコード-85と比較してください。どっちがいい?

呼び出しスタック

また、例外には通常、コードをより迅速かつ迅速にデバッグするのに役立つ詳細なコールスタックがあり、必要に応じて呼び出し元のコードで記録することもできます。これにより、開発者は通常、正確な行に問題を特定できるため、非常に強力です。もう一度、これを戻り値(-85、101、0など)を含むログファイルと比較します。どちらを好むでしょうか。

フェイルファーストバイアスアプローチ

失敗した場所でメソッドが呼び出されると、例外がスローされます。呼び出しコードは、明示的に例外を抑制するか、失敗します。開発およびテスト中(および実稼働中)にコードがすぐに失敗し、開発者が修正することを余儀なくされるため、私はこれが実際に驚くべきものであることに気付きました。戻り値の場合、戻り値のチェックに失敗した場合、エラーは黙って無視され、バグは予想外のどこかで表面化します。通常、デバッグと修正に非常に高いコストがかかります。

例外のラッピングとアンラッピング

例外は他の例外の中にラップし、必要に応じてアンラップできます。たとえばArgumentNullException、呼び出し元のコードUnableToRetrievePolicyExceptionで操作が失敗したため、呼び出し元のコードがラップする可能性があるコードがスローされる場合があります。上記の例に似たメッセージがユーザーに表示される場合がありますが、一部の診断コードは例外をラップ解除しArgumentNullException、問題の原因であることがわかります。つまり、消費者のコードのコーディングエラーです。これにより、アラートが発生し、開発者がコードを修正できます。このような高度なシナリオは、戻り値を使用して実装するのは簡単ではありません。

コードのシンプルさ

これは説明するのが少し難しいですが、このコーディングを通して、戻り値と例外の両方を学びました。通常、戻り値を使用して記述されたコードは呼び出しを行い、戻り値が何であるかについて一連のチェックを行います。場合によっては、別のメソッドを呼び出し、そのメソッドからの戻り値に対する別の一連のチェックを行うようになります。例外がある場合、例外処理は、すべてではないにしてもほとんどの場合、はるかに簡単です。try / catch / finallyブロックがあり、クリーンアップのためにfinallyブロックのコードを実行するためにランタイムが最善を尽くしています。ネストされたtry / catch / finallyブロックでさえ、複数のメソッドからのネストされたif / elseおよび関連する戻り値よりも、フォローおよび保守が比較的簡単です。

結論

使用しているプラ​​ットフォームが例外(特にJavaや.NETなど)をサポートしている場合、これらのプラットフォームには例外をスローするためのガイドラインがあり、クライアントは期待しているため、例外をスローする以外に方法がないことを明確に想定する必要がありますそう。あなたのライブラリを使用していた場合、例外がスローされることを期待しているため、戻り値を確認することはありません。これが、これらのプラットフォームの世界です。

ただし、C ++の場合、大きなコードベースが既にリターンコードとともに存在し、多数の開発者が例外ではなく値を返すように調整されているため(たとえば、WindowsにHRESULTがあふれているため)、判断が少し難しくなります。さらに、多くのアプリケーションでは、パフォーマンスの問題になる可能性があります(少なくとも認識されています)。


5
WindowsはC ++関数からHRESULT値を返し、パブリックAPIでのCの互換性を維持します(境界を越えて例外をマーシャリングしようとすると、痛い目に遭います)。アプリケーションを作成している場合、盲目的にオペレーティングシステムのモデルに従うことは避けてください。
コーディグレイ14年

2
これに追加する唯一のことは、疎結合の言及です。例外により、多くの予期しない状況を最も適切な場所で処理できます。例えば、ウェブアプリで、あなたは上の500を返すようにしたい任意のコードがために準備されなかった例外ではなく、Webアプリケーションをクラッシュ。そのため、コードの最上部(またはフレームワーク)で何らかのキャッチを行う必要があります。デスクトップGUIにも同様の状況が存在します。ただし、コード内のさまざまな場所に汎用性の低いハンドラーを配置して、試行中の現在のプロセスに適した方法でさまざまな障害状況を処理することもできます。
jpmc26 14年

2
あなたがC ++のコンストラクタからエラーの話をしている場合は@TrentonMakiは、最良の答えはここにある:parashift.com/c++-faq-lite/ctors-can-throw.html。つまり、例外をスローしますが、最初に潜在的なリークをクリーンアップすることを忘れないでください。私は、コンストラクターからのまっすぐな投げが悪いことである他の言語を知りません。APIのほとんどのユーザーは、エラーコードをチェックするよりも例外をキャッチすることを好みます。
オーガ詩sal 33 14年

3
「このような高度なシナリオは、戻り値を使用して実装するのは簡単ではありません。」もちろんできます!あなたがしなければならないのはErrorStateReturnVariableスーパークラスを作成することであり、そのプロパティの1つはInnerErrorState(のインスタンスですErrorStateReturnVariable)、サブクラスを実装することでエラーのチェーンを表示するように設定できます... :p
ブライアンS 14年

5
言語が例外をサポートしているからといって、例外を万能薬にするわけではありません。例外は隠された実行パスを導入するため、その効果を適切に制御する必要があります。try / catch追加するのは簡単ですが、回復を得ることは右であるハード ...、
マシューM.

21

エラー変数は、例外が利用できなかったCのような言語の遺物です。現在、Cプログラム(または例外処理のない同様の言語)から使用される可能性のあるライブラリを作成する場合を除き、それらを避ける必要があります。

もちろん、「警告」としてより適切に分類できるタイプのエラーがある場合(=ライブラリは有効な結果を提供でき、呼び出し側はそれが重要ではないと考える場合は警告を無視できます)、フォームのステータスインジケーター変数の例外は、例外のある言語でも意味があります。しかし、注意してください。ライブラリの呼び出し元は、そうすべきではない場合でも、このような警告を無視する傾向があります。そのため、このような構成をライブラリに導入する前によく考えてください。


1
説明ありがとう!あなたの答え+ Omer Iqbalが私の質問に答えました。
ミケイラマキ14

「警告」を処理する別の方法は、デフォルトで例外をスローし、例外のスローを停止するための何らかのオプションのフラグを持つことです。
ザリガニ14年

1
@Cyanfish:はい。ただし、特にライブラリを作成する場合は、そのようなことを過剰に設計しないように注意する必要があります。2、3、またはそれ以上よりも、単純で動作する警告メカニズムを1つ提供する方が適切です。
Doc Brown 14年

例外、例外、不明または回復不可能なシナリオが発生した場合にのみ例外をスローする必要があります- 例外的な状況。例外を構築するときは、パフォーマンスへの影響を期待するべきである
Gusdor

@Gusdor:絶対に、だからこそ、典型的な「警告」がデフォルトで例外をスローしないようにすべきです。しかし、これは抽象化のレベルにも少し依存します。サービスまたはライブラリは、異常なイベントを呼び出し元の観点から例外として扱うべきかどうかを判断できない場合があります。個人的には、このような状況では、警告インジケーター(例外なし)を設定するだけでlibを使用し、呼び出し元にそのフラグをテストさせ、適切と思われる場合は例外をスローします。これが、上記の「ライブラリに警告メカニズムを1つ提供する方が良い」と書いたときに思い描いていたことです。
Doc Brown 14年

20

エラーを通知する方法は複数あります。

  • チェックするエラー変数:CGo、...
  • 例外:JavaC#、...
  • 「条件」ハンドラー:Lisp(のみ?)、...
  • 多態的なリターン:HaskellMLRust、...

エラー変数の問題は、チェックするのを忘れやすいことです。

例外の問題は、実行の隠されたパスを作成することであり、try / catchは簡単に記述できますが、catch句で適切なリカバリを確実に実行することは非常に困難です(型システム/コンパイラからのサポートはありません)。

条件ハンドラーの問題は、それらがうまく構成されないことです。動的コード実行(仮想関数)がある場合、どの条件を処理する必要があるかを予測することは不可能です。さらに、同じ条件が複数のスポットで発生する可能性がある場合、毎回均一な解決策を適用できるということはわからず、すぐに面倒になります。

ポリモーフィックリターン(Either a bHaskell)は、これまでのところ私のお気に入りのソリューションです。

  • 明示的:実行の隠されたパスはありません
  • 明示的:関数型シグネチャで完全に文書化されています(驚くことはありません)
  • 無視するのは難しいです。目的の結果を得るためにパターンマッチを行い、エラーを処理する必要があります

唯一の問題は、過剰なチェックにつながる可能性があることです。それらを使用する言語には、それらを使用する関数の呼び出しをチェーン化するイディオムがありますが、それでももう少し入力/整理が必要な場合があります。Haskellでは、これはモナドになります。ただし、これは思ったよりもはるかに怖いです。鉄道指向プログラミングを参照してください。


1
いい答えだ!エラーを処理する方法のリストを取得できると期待していました。
ミケイラマキ14

ああ!「エラー変数の問題は、確認するのを忘れやすいことです」ということを、これまで何度も見ました。例外の問題は、キャッチするのを忘れやすいことです。その後、アプリケーションがクラッシュします。上司はそれを修正するためにお金を払いたくはありませんが、顧客はクラッシュにイライラするため、アプリの使用を停止します。すべては、エラーコードが返されて無視された場合、プログラムの実行に影響を与えないものが原因です。私がこれまでにエラーコードを無視するのを見たのは、それほど重要ではなかったときだけです。チェーンの上位のコードは、何かが間違っていることを知っています。
ダンク

1
@ダンク:私の答えが例外の謝罪にもならないと思います。ただし、作成するコードのタイプに依存する可能性があります。私の個人的な仕事の経験は、サイレントデータ破損が悪化(検出されない)し、作業中のデータがクライアントにとって価値があるため(もちろん、緊急の修正も意味するため)、エラーが発生して失敗するシステムを好む傾向があります。
マチューM.

サイレントデータ破損の問題ではありません。これは、アプリを理解し、操作が成功したかどうかをいつ、どこで確認する必要があるかを知ることの問題です。多くの場合、その決定と処理を遅らせることができます。例外が必要とする失敗した操作をいつ処理する必要があるかを私に伝えるのは、他の誰か次第ではありません。それは私のアプリです。関連する問題をいつどこで処理したいかを知っています。ユーザーがデータを破損する可能性のあるアプリを作成する場合、それは本当に貧しい仕事をしているだけです。クラッシュするアプリを作成すること(よく見かけます)もうまくいきません。
ダンク14

12

ひどいと思います。現在、例外の代わりに戻り値を使用するJavaアプリをリファクタリングしています。Javaを使用しているわけではないかもしれませんが、それでもこれは当てはまると思います。

次のようなコードになります。

String result = x.doActionA();
if (result != null) {
  throw new Exception(result);
}
result = x.doActionB();
if (result != null) {
  throw new Exception(result);
}

またはこれ:

if (!x.doActionA()) {
  throw new Exception(x.getError());
}
if (!x.doActionB()) {
  throw new Exception(x.getError());
}

私はむしろアクションが例外をスローするようにしたいので、あなたは次のようなものになります:

x.doActionA();
x.doActionB();

これをtry-catchでラップし、例外からメッセージを取得するか、たとえば既になくなっている可能性のあるものを削除する場合など、例外を無視することを選択できます。スタックトレースがある場合は、それも保持します。メソッド自体も簡単になります。例外自体を処理する代わりに、何が間違っていたかを投げます。

現在の(恐ろしい)コード:

private String doActionA() {
  try {
    someOperationThatCanGoWrong1();
    someOperationThatCanGoWrong2();
    someOperationThatCanGoWrong3();
    return null;
  } catch(Exception e) {
    return "Something went wrong!";
  }
}

新しくなり改善された:

private void doActionA() throws Exception {
  someOperationThatCanGoWrong1();
  someOperationThatCanGoWrong2();
  someOperationThatCanGoWrong3();
}

Strackトレースは保持され、メッセージは、役に立たない「何かがうまくいきませんでした!」ではなく、例外で利用可能です。

もちろん、より良いエラーメッセージを提供することができます。しかし、私が取り組んでいる現在のコードは苦痛であり、同じことをすべきではないので、この投稿はここにあります。


1
ただし、1つの問題として、「新しく改善された」状況では、例外が最初に発生した場所のコンテキストが失われる場合があります。たとえば、doActionA()の「現在の(恐ろしい)バージョン」では、catch句は、より有用なメッセージを提供するために、囲んでいるオブジェクトからインスタンス変数およびその他の情報にアクセスできます。
情報14年

1
それは本当ですが、ここでは現在起こりません。また、常にdoActionAで例外をキャッチし、ステータスメッセージで別の例外にラップすることができます。その後、スタックトレース有用なメッセージがまだあります。 throw new Exception("Something went wrong with " + instanceVar, ex);
mrjink 14年

同意します、あなたの状況では起こらないかもしれません。ただし、doActionA()に情報を「常に」入れることはできません。どうして?doActionA()の呼び出し元は、含める必要がある情報を保持している唯一の人かもしれません。
情報14年

2
したがって、例外を処理するときに呼び出し元に含めるようにしてください。ただし、元の質問にも同じことが当てはまります。例外でできないことでできることは何もないので、コードがきれいになります。返されたブール値やエラーメッセージよりも例外を好みます。
mrjink 14年

通常、「someOperation」のいずれかで発生する例外は同じ方法で処理およびクリーンアップできるという誤った仮定をします。実生活で起こることは、各操作の例外をキャッチして処理する必要があるということです。したがって、例のように例外をスローするだけではありません。また、例外を使用すると、一連のネストされたtry-catchブロックまたは一連のtry-catchブロックのいずれかが作成されます。これにより、コードがはるかに読みにくくなります。私は例外に対して設定されていませんが、特定の状況に適切なツールを使用します。例外はたった1つのツールです。
ダンク14

5

「発生する可能性のあるいくつかのエラーを処理するために、実行を停止しないでください」

エラーが現在の関数の実行を停止してはならないが、何らかの方法で呼び出し元に報告する必要があることを意味する場合は、実際には言及されていないいくつかのオプションがあります。このケースは、実際にはエラーというよりも警告です。スロー/リターンは現在の機能を終了するため、オプションではありません。単一のエラーメッセージパラメーターまたは戻り値では、これらのエラーのうち1つだけが発生します。

私が使用した2つのパターンは次のとおりです。

  • エラー/警告コレクション。渡されるか、メンバー変数として保持されます。どれを追加して処理を続けるか。私は個人的にこのアプローチが好きではないので、それが発信者の力を弱めると感じています。

  • エラー/警告ハンドラーオブジェクトを渡します(または、メンバー変数として設定します)。そして、各エラーはハンドラーのメンバー関数を呼び出します。これにより、呼び出し側は、このような非終了エラーの処理方法を決定できます。

これらのコレクション/ハンドラーに渡すものには、エラーを「正しく」処理するのに十分なコンテキストが含まれている必要があります。 。

エラーハンドラを使用した典型的なコードは次のようになります

class MyFunClass {
  public interface ErrorHandler {
     void onError(Exception e);
     void onWarning(Exception e);
  }

  ErrorHandler eh;

  public void canFail(int i) {
     if(i==0) {
        if(eh!=null) eh.onWarning(new Exception("canFail shouldn't be called with i=0"));
     }
     if(i==1) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=1 is fatal");
        throw new RuntimeException("canFail called with i=2");
     }
     if(i==2) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=2 is an error, but not fatal"));
     }
  }
}

3
ユーザーがエラーではなく警告を望んでいることに気付くために+1。warningsこの問題の別のパターンを提供するPythonのパッケージに言及する価値があるかもしれません。
James_pic 14年

すばらしい答えをありがとう!これは、私が見たかったものであり、従来のtry / catchでは不十分なエラーを処理するための追加パターンです。
ミケイラマキ14

渡されたエラーコールバックオブジェクトは、特定のエラーまたは警告が発生したときに例外をスローできることを言及すると便利な場合があります。何かをするための呼び出し関数 たとえば、「ハンドル解析エラー」メソッドは、呼び出し元に、解析が返されたとみなすべき値を与える可能性があります。
supercat

5

他の人が使用するパターンを使用している限り、このパターンまたはそのパターンを使用しても何も問題はありません。でObjective-Cの開発、多くの好ましいパターンが呼び出されるメソッドがNSErrorオブジェクトを堆積させることができるポインタを渡すことです。例外はプログラミングエラーのために予約されており、クラッシュを引き起こします(Javaまたは.NETプログラマーが最初のiPhoneアプリを作成している場合を除く)。そして、これは非常にうまく機能します。


4

質問はすでに答えられていますが、私は自分自身を助けることができません。

例外がすべてのユースケースのソリューションを提供することを本当に期待することはできません。誰でもハンマー?

例外がすべてではなくすべてである場合があります。たとえば、メソッドがリクエストを受信し、最初のフィールドだけでなく、渡されたすべてのフィールドの検証を担当する場合、複数のフィールドのエラーの原因を示します。検証の性質により、ユーザーがそれ以上進むことができないかどうかを示すことも可能です。その例は、強力ではないパスワードです。入力したパスワードはそれほど強力ではないが、十分強力であることを示すメッセージをユーザーに表示できます。

これらの検証はすべて、検証モジュールの最後に例外としてスローされる可能性があると主張できますが、名前以外のエラーコードになります。

したがって、ここでの教訓は次のとおりです。エラーコードと同様に、例外には場所があります。賢明に選んだ。


これはむしろ悪いデザインを暗示していると思います。引数を取るメソッドは、それらを処理できるかどうかを判断できる必要があります-間には何もありません。例では、Validator問題のメソッド(またはその背後のオブジェクト)に(インターフェース)を挿入する必要があります。挿入されValidatorた方法に応じて、メソッドは不正なパスワードを使用して処理を行います-または処理しません。周囲のコードはWeakValidator、ユーザーがWeakPasswordException最初に試したによってスローされた場合などに、ユーザーが要求した場合に試行できStrongValidatorます。
JHR

ああ、しかし、これがインターフェースやバリデーターになれないとは言いませんでした。JSR303についても言及しませんでした。そして、あなたが注意深く読んだ場合、私は弱いパスワードを言わないで、むしろ、それはあまり強くないことを確認しました。弱いパスワードは、フローを停止し、ユーザーに強力なパスワードを要求する理由になります。
アレクサンドルサントス14年

そして、中程度に強力ではあるが、本当に弱いパスワードでは何をしますか?フローを中断し、入力したパスワードがあまり強力ではないことを示すメッセージをユーザーに表示します。だからMiddlyStrongValidator何かを持っています。そして、それが実際にフローを中断しなかった場合、Validator事前に呼び出されている必要があります。これは、ユーザーがまだパスワード(または同様)を入力している間にフローを進める前です。しかし、そもそも検証は問題のメソッドの一部ではありませんでした。:)おそらく、すべての後に好みの問題...
JHR

@jhr私が書いたバリデーターでは、通常AggregateException(または同様のValidationException)を作成し、InnerExceptionsに各検証問題の特定の例外を入れます。たとえば、BadPasswordException「ユーザーのパスワードは最小長の6未満です」またはMandatoryFieldMissingException「ユーザーの名を指定する必要があります」などです。これはエラーコードとは異なります。これらのメッセージはすべて、ユーザーが理解できる方法で表示できますNullReferenceException。代わりにa がスローされると、バグが発生します。
オメルイクバル14年

4

エラーコードが例外よりも望ましいユースケースがあります。

エラーにもかかわらずコードを続行できるが、レポートが必要な場合、例外はフローを終了するため、例外は適切ではありません。たとえば、データファイルを読み込んでいて、そこに不正なデータの非終端部分が含まれていることがわかった場合、完全に失敗するのではなく、ファイルの残りの部分を読み込んでエラーを報告する方がよい場合があります。

他の回答では、一般にエラーコードよりも例外を優先する理由について説明しました。


警告を記録する必要がある場合など。しかし、エラーが「レポートを必要とする」場合、つまりユーザーにレポートすることを意味する場合、周囲のコードがリターンコードを読み取って実際にレポートすることを保証する方法はありません。
jhr

いいえ、発信者に報告することを意味します。例外の場合と同様に、ユーザーがエラーについて知る必要があるかどうかを決定するのは呼び出し側の責任です。
ジャックエイドリー14年

1
@jhr:何か保証があるのはいつですか?クラスの契約では、クライアントに特定の責任があることを指定できます。クライアントが契約を順守する場合、契約に必要なことを行います。そうでない場合、結果はクライアントコードの障害になります。クライアントによる偶発的なミスを防ぎたい場合、およびシリアル化メソッドによって返される型を制御できる場合は、「認識されていない可能性のある破損」フラグを含め、クライアントがAcknowledgePossibleCorruptionメソッドを呼び出さずにデータを読み取れないようにすることができます。 。
supercat

1
...しかし、問題についての情報を保持するオブジェクトクラスを持つことは、例外を投げたり、合否エラーコードを返すよりも役立つかもしれません。その情報を適切な方法で使用するかどうかはアプリケーション次第です(たとえば、ファイル "Foo"を読み込むとき、データが信頼できない可能性があることをユーザーに通知し、保存時にユーザーに新しい名前を選択するように促します)。
supercat

1
例外を使用する場合、1つの保証があります。例外をキャッチしない場合、例外が発生します-最悪の場合はUIまで。誰も読み取らないリターンコードを使用する場合、このような保証はありません。もちろん、使用する場合はAPIに従ってください。同意する!しかし、エラー、残念ながら...の余地があります
JHR

2

例外が適切でない場合、例外を使用しないことで間違いはありません。

コードの実行が中断してはならない場合(例えば、コンパイルするプログラムまたはプロセスへのフォームのように、複数のエラーが含まれていてもよい、ユーザ入力に作用する)、私のようなエラー変数のエラーを収集することを見つけるhas_errorsとすると、error_messages実際に投げるよりもはるかにエレガントなデザインです最初のエラーでの例外。ユーザーが不必要に再送信することを強制することなく、ユーザー入力のすべてのエラーを見つけることができます。


質問に興味を持ってください。私の質問の問題と理解は、用語が不明確だと思います。あなたが説明することは例外ではありませんが、それはエラーです。それを何と呼ぶべきでしょうか?
ミケイラマキ14

1

一部の動的プログラミング言語では、エラー値例外処理の両方を使用できます。これは、通常の戻り値の代わりにスローされない例外オブジェクトを返すことで行われます。エラー値のようにチェックできますが、チェックされない場合は例外をスローします。

Perl 6のそれを介して行われるfailwithing場合れ、no fatal;スコープがスローされない特別な例外リターンFailureオブジェクト。

Perl 5を使用できコンテキスト::リターンをあなたがこれを行うことができますreturn FAIL


-1

非常に具体的なものがない限り、検証用のエラー変数を持つことは悪い考えだと思います。目的は、検証に費やした時間を節約することであるようです(変数値を返すだけです)

ただし、何かを変更した場合は、とにかくその値を再計算する必要があります。ただし、停止と例外のスローについては言えません。

編集:私はこれが特定のケースではなくソフトウェアパラダイムの問題であることを理解していませんでした。

私の答えが理にかなっている私の特定のケースで私のポイントをさらに明確にしましょう

  1. エンティティオブジェクトのコレクションがあります
  2. これらのエンティティオブジェクトを操作する手続き型のWebサービスがあります

エラーには次の2種類があります。

  1. サービス層で処理が行われるときのエラー
  2. エンティティオブジェクトに矛盾があるため、エラー

サービス層では、エラー変数と同等の結果オブジェクトをラッパーとして使用する以外に選択肢はありません。httpのようなプロトコルでサービス呼び出しを介して例外をシミュレートすることは可能ですが、間違いなく良いことではありません。私はこの種のエラーについて話しているのではなく、これがこの質問で尋ねられている種類のエラーだとは思わなかった。

2番目の種類のエラーについて考えていました。そして私の答えは、この2番目の種類のエラーについてです。エンティティオブジェクトには、私たちのための選択肢があり、そのうちのいくつかは

  • 検証変数を使用する
  • セッターからフィールドが正しく設定されていない場合、すぐに例外をスローします

検証変数を使用することは、各エンティティオブジェクトに対して単一の検証メソッドを使用することと同じです。特に、ユーザーはセッターを純粋なセッターとして維持する方法で値を設定でき、副作用はありません(これは多くの場合良い方法です)。これの利点は、時間を節約することです。検証結果は検証変数にキャッシュされるため、ユーザーがvalidation()を複数回呼び出したときに複数の検証を行う必要はありません。

この場合の最善の方法は、検証エラーをキャッシュするために検証を使用しなくても、単一の検証メソッドを使用することです。これは、セッターを単なるセッターとして保持するのに役立ちます。


あなたの言っていることがわかります。興味深いアプローチ。回答セットの一部であることがうれしいです。
ミケイラマキ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.