web-dev-qa-db-ja.com

Javaメソッドの呼び出し元に計算結果と一緒に警告を返す方法は?

私はクラスを持っているので、次のようなメソッドでCalculatorと呼びます。

_public double[] performCalculation(double[] someInData)
_

このメソッドは、いくつかの致命的でない警告を生成できます(InDataOutOfBoundsなどの警告名が付いた文字列の配列として表されます)。これらの警告を呼び出し元に返す最もエレガントでジャバスクな方法は何ですか?私はいくつかの可能性を見つけましたが、私が特に好きなものはありません:

  1. 計算の結果と警告の配列の両方を含むカスタムクラスのインスタンスを返します。
  2. performCalculationに、警告が入力される追加の引数_String[] warnings_を受け入れさせます。渡された配列のサイズを変更できないようで、警告がいくつあるかを事前に知る方法がないため、これはうまくいかないかもしれません。
  3. performCalculationはそのままにしますが、CalculatorにメソッドString[] getWarnings()を追加すると、最新の計算からの警告が返されます。

編集:私は this の質問を認識しています。その質問に対する一番上の答えは、答えは状況に依存していると言っているので、これは重複ではないと主張します。これはより具体的なケースであり、より具体的な答えを得ることができます。

27
Anders
  1. はい。これを行う。それはJavaであり、クラスを恐れないでください。これがクラスの目的です。

  2. すごく悪い。それはやや配列の代わりにCollectionを使用するとそれほど悪くはありませんが、完全に正しく使用されることのない、その場しのぎで指定されていないセマンティクスを求めています。

  3. 動作可能if単一の制御フローの状況を除いて、絶対に、確実に、絶対にCalculatorを使用しないことを確信しています。残念ながら、並列化は、事後に必要となる最も一般的な変更の1つです。

50
Kilian Foth

オプション1が最良の解決策だと思います。警告を含むすべての結果をカスタムオブジェクトで返します。メソッド呼び出しを実行するオブジェクト内で状態を維持していないため、状態を保持および管理することを心配する必要はありません(たとえば、スレッドシナリオで、またはメソッドを2回続けて呼び出して結果を誤って失うことさえあります)。 。

この種のもののためにカスタムオブジェクトを構築することを恐れないでください。フィールドを含むだけでなく、このオブジェクトにメソッドを追加して、この情報を結び付け、ステータスを報告することもできます。 returnResults.hasWarnings())。

より多くの機能がこの戻りオブジェクトに該当することに気付くでしょう。私が同様のことをしている場合(たとえば、Scalaの場合)、私はしばしばTuple(結果のセットが結合されている)を返すことから始め、これを非常に迅速に追加の機能を備えた新しいクラスに変換します)

27
Brian Agnew

4番目のオプションは、#2で提案されているString[] warnings(またはより柔軟に変更可能なList<String> warnings)を渡すのではなく、警告を受け取って表示するコールバックリスナーまたはオブジェクトを渡すことです。 。高速な計算の場合、これはやり過ぎである可能性が非常に高いですが、計算が長時間かかる場合や、非同期通知の表示を開始する必要がある場合は、この方法が適している可能性があります。このパターンを使用する場合、後で検査するために何もしないリスナー実装と集約リスナー実装を提供し、リスナーをnull可能またはオプションにする(オーバーロード経由)ことを検討することもできます。

public interface WarningListener {
  void warn(String warning);
  void showProgress(int percentage);
}

public Result performCalculation(Input input, WarningListener listener) { ... }

ただし、計算を早めに呼び出す特別な理由がない限り、オプション#1を使用します。構造体がない場合は、軽量のJavaクラスが複数の値を返すのに最適な方法です。単一のユニット。

16
Jeff Bowman

他の人がすでに指摘したように、#1が最善の策です。

実装側では、 通知パターン を確認することをお勧めします。

通知は「ドメインレイヤー内のエラーやその他の情報に関する情報を収集し、それをプレゼンテーションに伝えるオブジェクトです。」

したがって、本質的なアイデアは、エラー(または必要に応じて警告)を1つのオブジェクトにまとめることです。

6
Lovis

呼び出し元が警告に反応できるようにする必要がある場合、推奨される方法は最初の提案です。つまり、カスタムタイプを返します(他の人がすでに指摘しているように)。

ただし、ほとんどの場合、呼び出し元は警告に関心がありません。これらの場合、通常、このような警告はロガーに送信されます(例 slf4j を参照)。

public double[] performCalculation(double[] someInData) {
    // ...
    if (dataOutOfRange) {
        LOGGER.warn("Input data {} is out of range!", data);
    }
    // ...
    return result;
}

別の方法は、Java 8ラムダ式を使用して、呼び出し元が何らかのリスナーを通過できるようにすることです。

public double[] performCalculation(double[] someInData, Consumer<Warning> warningConsumer) {
    // ...
    if (dataOutOfRange) {
        warningConsumer.accept(new Warning(WarningType.OUT_OF_RANGE, value));
    }
    // ...
    return result;
}
2
user3151902

私は過去に別のアプローチを使用しました。私のシナリオでは、警告を生成する可能性のある多数のメソッドがありました。警告のリストなど、さまざまなものを含むContextクラスを作成しました。また、静的メソッドgetCurrentContext()もあります。

したがって、警告を生成する必要があるときはいつでも、私は行うことができます:

Context.getCurrentContext().addWarning("Email address is longer than 64 characters; truncating");

この配置の利点は、警告をどこにでも作成できることです。

主な問題は、getCurrentContextの実装です。私のアプリケーションは、各リクエストが個別のスレッドで処理されるWebアプリケーション(REST/JSONサービス)でした。リクエストの開始時に、空のコンテキストが作成され、スレッドIDに基づいて保存されます。 getCurrentContextは、現在のスレッドIDを使用してコンテキストを取得します。リクエストの最後で、出力JSONが構築されると、警告がJSONに含まれます。

あなたのシナリオで、performCalculationが警告を引き起こす可能性のある唯一のメソッドである場合、これはおそらくあなたのための解決策ではありません。

この一般的なアプローチに関するフィードバックに興味があります。この特定のアプリでは非常にうまく機能しますが、少しハックを感じます。

1
paj28

オプション1が最適だと思いますが、私の意見では、カスタムのResultsクラスを作成するよりも、より良い方法があると思います。

他の人が述べたように、結果と警告のリストの2Tupleを使用するだけです。

public Tuple2<double[],String[]> performCalculation(double[] someInData){
    ...
}

これはタプルを実装する方法の例です

一般的にクラスは再利用可能であるべきなので、これはより良いと思います。これらの結果を取得するために一度使用する結果クラスはそうではありません。しかし、タプルは一般的であり、多くのインスタンスで再利用できます。

1
Ryan Stull