web-dev-qa-db-ja.com

IllegalStateExceptionのグッドプラクティス

IllegalStateException の用途はわかっていますが、場合によっては実際に使用する必要があるのか​​、それとも単なる設計の問題なのかと思います。

スポーツトーナメントをモデル化するTournamentクラスがあり、トーナメントに計算する必要があるScheduleがあるとします。したがって、スケジュールを生成する解決プロセスを実際に起動しない限り、スケジュールはありません。この状態が実際に発生する前にそれを取得しようとすることは、何らかの方法で処理する必要があります。これは、IllegalStateExceptionをスローする適切なシナリオだと思いました。スケジュールがまだ計算されていない場合は、スローしてください。どれどれ:

public Tournament {
    private Schedule schedule;

    public boolean solve() {
        boolean solved = solver.solve();
        if (solved)
            schedule = solver.getSolution();
        return solved;
    }

    public Schedule getSchedule() {
        if (schedule == null)
            throw new IllegalStateException("Schedule has not been calculated yet");
        return schedule;
    }

    // This udpates the current schedule with the "next" solution. 
    // Same logic regarding the ISE is applied
    public boolean nextSchedule() {
        if (schedule == null)
            throw new IllegalStateException("Schedule has not been calculated yet");
        boolean hasNextSolution = solver.update();
        if (hasNextSolution)
            schedule = solver.getSolution();
       return hasNextSolution;
    }
}

ここでISEが適切に使用されていますか?代わりにクラスのデザインを変更する必要がありますか?

ベストプラクティスは何ですか?

5
dabadaba

現状では、クラスは基本的に反復可能です。

  1. getSchedule()は多かれ少なかれnext()
  2. nextSchedule()は多かれ少なかれhasNext()
  3. solvehasNext()iterator()の組み合わせです

標準的なイテレータの使用パターンは次のとおりです。

Iterator iter = item.iterator();
while(iter.hasNext()) {
  doSomething(iter.next())
}

あなたの使用パターンは:

if (item.solve()) {
   doSomething(item.getSchedule());
   while (item.nextSchedule()) {
       doSomething(item.getSchedule());
   }
}

したがって、基本的に、クラスはイテラブルの貧弱なバージョンです。解決策:イテラブルを使用します。

class Tournament {
    Iterable<Schedule> calculateSchedules();
}

今、私たちは誰もが知っていて、一般的なコードで使用できる標準インターフェースを使用しています。

9
Winston Ewert

オブジェクトを誤って使用することは不可能になるようにすることをお勧めします。

問題を説明する方法は次のとおりです。

Widget w = ...;
w.method1();
w.method2();
// Happy happy joy joy!

ただし、これを行うことは可能です:

Widget w = ...;
w.method2();
// Stimpy you eeediot! You broke the widget!

解決策は、オブジェクトをより多くの部分に分割し、一時的な依存関係を作ることです。オブジェクトAはオブジェクトBを提供し、オブジェクトBはオブジェクトCを提供します。おそらく間違った順序で、AからBとCの両方を取得することはできません。

これは基本的に、静的(コンパイラー強制)チェックを使用して、時間的なデカップリングを強制します。

それが一般的な解決策でした-特定の例では、ScheduleTournamentへの必須のコンストラクター引数にします。そこに循環依存関係がある場合(コードからは不明)、必要なデータを収集し、オブジェクトを完全に構築して初期化してから使用できるようにするジェネレーターまたは builder class を作成します。

詳細については、同様の質問の 私の答え を参照してください。

4
user22815

ベストプラクティスは、オブジェクトが不正な状態にならないようにすることです。

もちろん、この例外をスローすることはありませんが、それが存在するからといって、それを使用することが良いことであるとは限りません。

賢い人がおそらくそれを使用することを要求するケースを思いつくかもしれませんが、ここでの私のポリシーは「可能な限り避ける」ことです。

では、これをどのように再設計する必要がありますか?

キャッシュしてみてください。 getSchedual()は、スケジュールの作成も試みません。それはそれが存在する前にそれを求めるためにあなたを罰するだけです。正常に存在する場合は返却してください。そうでなければ、少なくともそれを作成してみませんか?

Solver.solve()が他の誰かの赤ちゃんである場合、私は理解していますが、あなたがそうである場合、cスタイルのエラーブール値をOOPスタイルの例外と混在させるのはなぜですか?スタイルを1つ選び、それに固執します。

最後の一口。ほとんどの場合、何が行われているのかを確認するよりも、動作オブジェクトに何かを実行するように指示する方が適切です。トーナメントを使用するとき、なぜスケジュールを知る必要があるのですか?なぜ勝者を印刷するように指示できないのですか?

2
candied_orange
  • IllegalStateExceptionの使用は問題ないと思います。
  • 時々、一時的な結合が避けられないことがあります。たとえば、Java JDKのMatcherクラスを見てみましょう。存在しないパターンに一致するものを見つけようとすると、この例外がスローされます。
  • Nullスケジュールを返し、クライアントコードにNullPointerExceptionを処理させるか、nullをチェックしてそれに応じて動作させる必要があると主張する人もいますが、私にとってはJava Matcher/Pattern正規表現を使用して文字シーケンスの一致操作を行うクラス。

ただし、クライアントコードが例外を回避できるようにboolean hasSchedule()メソッドを追加することをお勧めします。しかし、それは素晴らしいことであり、本当に必要なことではないと思います。

ここでは、IllegalStateExceptionの正当な使用法をいくつか紹介します。

https://stackoverflow.com/questions/12698275/whats-the-intended-use-of-illegalstateexception

2