play()メソッドとstop()メソッドを持つMediaPlayerクラスがあるとします。playメソッドが以前に呼び出されていない場合にstopメソッドを実装するときに使用する最適な戦略は何ですか。2つのオプションがあります。プレーヤーが適切な状態にないために例外をスローするか、stopメソッドの呼び出しを静かに無視します。
ある状況でメソッドが呼び出されることは想定されていないが、その実行がプログラム全般に害を及ぼさない場合の一般的なルールは何でしょうか?
play()メソッドとstop()メソッドを持つMediaPlayerクラスがあるとします。playメソッドが以前に呼び出されていない場合にstopメソッドを実装するときに使用する最適な戦略は何ですか。2つのオプションがあります。プレーヤーが適切な状態にないために例外をスローするか、stopメソッドの呼び出しを静かに無視します。
ある状況でメソッドが呼び出されることは想定されていないが、その実行がプログラム全般に害を及ぼさない場合の一般的なルールは何でしょうか?
回答:
ルールはありません。APIを「感じさせる」方法次第です。
個人的には、音楽プレーヤーで、私は状態からだと思うStopped
のStopped
方法によるがStop()
完全に有効な状態遷移です。あまり意味はありませんが、有効です。これを念頭に置いて、例外をスローすることは、つまらなく不公平に思えます。APIは、スクールバスで迷惑な子供と話すのと同じような社会的な感覚をAPIに与えます。あなたは迷惑な状況で立ち往生していますが、あなたはそれに対処することができます。
より「社交的な」アプローチは、移行が最悪の場合無害であることを認め、それを許可することで消費する開発者に親切にすることです。
それで、もしそれが私次第なら、私は例外をスキップします。
MediaPlayer.stop()
IllegalStateException
StopOrThrow()
恐ろしいですね。あなたがその路地を下っているなら、なぜ標準パターンを使用しないのTryStop()
ですか?また、一般に、APIの動作が不明確な場合(ほとんどがそうであるように)、開発者は単純に推測または実験することを期待されず、ドキュメントを見ることが期待されます。だからこそ、MSDNが大好きです。
実行したいアクションは2種類あります。
何かがある状態にあることを同時にテストし、別の状態に変更します。
前の状態に関係なく、何かを特定の状態に設定します。
コンテキストによっては、1つのアクションが必要なものと、他のアクションが必要なものがあります。コンテンツの最後に到達したメディアプレーヤーが「再生」状態のままで、位置が最後にフリーズした場合、「停止」に設定すると同時にプレーヤーが再生状態にあったことをアサートするメソッド状態は、コードが停止要求の前に再生を失敗させないようにする場合に役立ちます(たとえば、メディアをある形式から別の形式に変換する手段として再生中のコンテンツを記録している場合に重要です) 。ただし、ほとんどの場合、重要なのは、操作後、メディアプレーヤーが予期された状態(つまり停止)になっていることです。
メディアの最後に到達したときにメディアプレーヤーが自動的に停止する場合、プレーヤーが実行されていると断言する機能は役に立たないというよりも面倒ですが、場合によっては停止時にプレーヤーが実行されているかどうかを知ることもできます便利である。おそらく、両方のニーズに応える最善の方法は、プレーヤーの前の状態を示す値を関数に返すことです。その状態を考慮するコードは戻り値を調べることができます。気にしないコードは単純に無視できます。
bool TryStop()
とvoid Stop()
コード例は、これを本当に優れた答えにします。
TryStop
は、プレーヤーを強制的に停止状態にできない場合、例外をスローしないことを意味します。プレーヤーが既に停止しているときに停止しようとすることは例外的な条件ではありませんが、発信者が関心を持つ可能性がある条件です
isPlaying()
。
例外の目的は、何か悪いことが起こったことを知らせることではありません。それは合図することです
呼び出し元が既に停止状態にStop
あるものMediaPlayer
を試みた場合、これはMediaPlayer
解決できない問題ではありません(単純に何もできません)。継続すると、損傷やデータにつながる問題ではありません。何もしないだけで成功する可能性があるため、破損。そして、呼び出し側がを解決できると期待する方が合理的であることは、実際には問題ではありませんMediaPlayer
。
したがって、この状況では例外をスローしないでください。
ルールは、メソッドの契約に必要なことを行うことです。
このようなstop
メソッドに意味のあるコントラクトを定義する複数の方法を見ることができます。stop
プレーヤーがプレイしていない場合、メソッドがまったく何もしないことは完全に有効です。その場合、目標によってAPIを定義します。stopped
状態に遷移したい場合、stop
メソッドはそれを行います- stopped
状態からそれ自体にエラーなしで遷移するだけです。
あなたはなぜ何らかの理由があるしたい例外をスローするには?ユーザーコードが最終的に次のようになる場合:
try {
player.stop();
} catch(IllegalStateException e) {
// do nothing, player was already stopped
}
その例外が発生してもメリットはありません。質問は、ユーザーがプレーヤーが既に停止しているという事実を気にしますか?彼はそれを照会する別のwaを持っていますか?
プレーヤーは観察可能であり、特定の事柄について既にオブザーバーに通知している場合があります。たとえば、からplaying
に遷移するときにオブザーバーに通知stopping
しstopped
ます。この場合、メソッドに例外をスローさせる必要はありません。stop
プレーヤーが既に停止している場合、呼び出しは何も行いません。停止していないときに呼び出すと、遷移についてオブザーバーに通知されます。
全体として、それはあなたのロジックがどこに行き着くかによります。しかし、例外をスローするよりも優れた設計の選択肢があると思います。
呼び出し元が介入する必要がある場合は、例外をスローする必要があります。この場合、彼はそうする必要はありませんが、プレーヤーをそのままにしておくと、そのまま動作し続けます。
この決定を下すのに役立つ簡単な一般的な戦略があります。
例外をスローする場合の例外の処理方法を検討してください。
だからあなたの音楽プレーヤーを想像してください、ユーザーが停止をクリックし、再び停止します。そのシナリオでエラーメッセージを表示しますか?私はまだそうするプレーヤーを見ていません。アプリケーションの動作を、「停止」を1回クリックするだけの場合とは異なるものにしたいですか(イベントのログ記録やバックグラウンドでのエラーレポートの送信など)。おそらくない。
つまり、例外をキャッチして、どこかに飲み込む必要があります。そして、それはあなたが別のアクションを取りたくないので、そもそも例外を投げないほうが良いことを意味します。
これは、例外だけでなく、あらゆる種類の分岐に適用されます。基本的に、動作に目に見える違いがないようにする必要がある場合は、分岐する必要はありません。
そうは言っても、停止が「成功」したかどうかを示す列挙値またはenum値stop()
を返すようにメソッドを定義しても、それほど害はありませんboolean
。おそらくこれを使用することはないでしょうが、戻り値は例外よりも簡単に自然に無視できます。
Androidの仕組みは次のとおりです。MediaPlayer
一言で言えば、中に呼び出されていない問題ではないが、停止した状態でのシステムのまま、それでも呼び出すための正当な理由がないので、例外がスローされ、それが再生されているものを知っていないプレーヤーで呼び出された場合そこで止まれ。stop
start
ある状況でメソッドが呼び出されることは想定されていないが、その実行がプログラム全般に害を及ぼさない場合の一般的なルールは何ですか?
あなたの答えをあなたに明らかにするかもしれないあなたの声明のマイナーな矛盾であるかもしれないものを見ます。なぜそれがあることであるメソッドが呼び出されることになっていませんし、まだそれの実行は問題はありませんか?
メソッドが「呼び出されるべきではない」のはなぜですか?それは自主規制のようです。APIに「害」や影響がない場合、例外はありません。無効または予測不可能な状態を作成する可能性があるため、メソッドを実際に呼び出すべきでない場合は、例外をスローする必要があります。
たとえば、DVDプレーヤーに近づいて「開始」を押す前に「停止」を押してクラッシュした場合、それは意味がありません。ただそこに座っているか、さらに悪い場合には、画面上の「停止」を確認する必要があります。エラーは迷惑であり、決して役に立ちません。
ただし、既にオフになっているときに(メソッドを呼び出して)アラームコードを入れて「オフ」にすることはできますか?その場合は、技術的には「問題は発生しなかった」にもかかわらず、後で問題が発生する可能性があるため、エラーをスローします。実際にその状態にならなかったとしても、これについて知りたいと思います。可能性だけで十分です。これはになりますIllegalStateException
。
あなたのケースでは、ステートマシンが無効/不必要な呼び出しを処理できる場合は無視し、そうでない場合はエラーをスローします。
編集:
値を検査せずに変数を2回設定しても、コンパイラーはエラーを呼び出しません。また、変数を再初期化することも妨げません。1つの観点から「バグ」と見なされる可能性のあるアクションは数多くありますが、単に「非効率的」、「不要」、「無意味」などです。予想外の結果をもたらさないため、「バグ」。おそらく同様に問題に取り組む必要があります。
何を正確に行うMediaPlayer.play()
とMediaPlayer.stop()
行う- ?彼らはイベントのユーザー入力のリスナーや、彼らは実際にはシステム上のメディアストリームのいくつかの並べ替えを開始する方法がありますか?すべてがユーザー入力のリスナーである場合、何もしないことは完全に合理的です(ただし、少なくともどこかにログを記録することをお勧めします)。彼らが影響を与える場合は、モデルをあなたのUIは、彼らが投げることができ、制御しているIllegalStateException
プレイヤーは、いくつかの並べ替えが必要ですので、isPlaying=true
またはisPlaying=false
お電話の際は(それがここに書かれてのような実際のブールフラグである必要はない)状態、およびそのMediaPlayer.stop()
際にisPlaying=false
、MediaPlayer
オブジェクトが停止するのに適切な状態にないため、メソッドは実際に「停止」できません-の説明を参照してくださいjava.lang.IllegalStateException
クラス:
違法または不適切なときにメソッドが呼び出されたことを通知します。つまり、Java環境またはJavaアプリケーションは、要求された操作に対して適切な状態ではありません。
多くの人は例外を投げるべきではないので、例外は一般に悪いと考えているようです(ソフトウェアのJoelを参照)。ただし、MediaPlayerGUI.notifyPlayButton()
whichがMediaPlayer.play()
をMediaPlayer.play()
呼び出し、他のコードの束を呼び出し、それがPulseAudioなどとインターフェイスする行のどこかにあるとしましょう。
その後、ある日、コードの作業中に「再生」をクリックしても何も起こりません。場合はMediaPlayerGUIController.notifyPlayButton()
、ログの何か、少なくとも私は、ログを調べて、ボタンのクリックが実際に登録していたことを確認してください...しかし、なぜそれが再生されないことができますか?さて、実際にMediaPlayer.play()
起動するPulseAudioラッパーに何か問題があるとしましょう。「再生」ボタンをもう一度クリックすると、今度は次のメッセージが表示されますIllegalStateException
。
Exception in thread "main" java.lang.IllegalStateException: MediaPlayer already in play state.
at org.superdupermediaplayer.MediaPlayer.play(MediaPlayer.java:16)
at org.superdupermediaplayer.gui.MediaPlayerGUIController.notifyPlayButton(MediaPlayerGUIController.java:25)
at org.superdupermediaplayer.gui.MediaPlayerGUI.main(MediaPlayerGUI.java:14)
そのスタックトレースを見ることで、MediaPlayer.play()
デバッグする前にすべてを無視し、たとえばオーディオストリームを開始するためにメッセージがPulseAudioに渡されない理由を理解するのに時間を費やすことができます。
一方、例外をスローしない場合、「バカなプログラムは音楽を再生しません」以外に作業を開始することはできません。実際にスローされた例外を実際に飲み込むなどの明示的なエラー隠蔽ほど悪くはありませんが、何かがうまくいかないときに他の人の時間を浪費している可能性があります...
私は、消費者が間違いを犯すのを困難または不可能にする方法でAPIを設計することを好みます。たとえば、代わりに持つのMediaPlayer.play()
とMediaPlayer.stop()
、あなたが提供することができMediaPlayer.playToggle()
、「停止」と「再生」の間で切り替わりいます。このように、メソッドは常に安全に呼び出すことができます-違法な状態になるリスクはありません。
もちろん、これは常に可能または簡単ではありません。指定した例は、リストから既に削除された要素を削除しようとすることに匹敵します。あなたはどちらかです
if (list.contains(x)) { list.remove(x) }
必要なだけを書く必要はありませんlist.remove(x)
)。しかし、バグを隠すこともできます。MediaPlayer.stop()
既に停止しているときに呼び出すことがアプリケーションに害を及ぼさない場合、コードを簡素化し、べき等なメソッドのためのものがあるので、静かに実行させます。しかしMediaPlayer.stop()
、これらの条件で呼び出されることは絶対にないと確信している場合、コードのどこかにバグがあり、例外がそれを追跡するのに役立つ可能性があるため、エラーをスローします。
playToggle()
使いやすくすることに同意しません:目的の効果(プレーヤーの演奏または演奏なし)を達成するには、その現在の状態を知る必要があります。そのため、プレーヤーの停止を要求するユーザー入力を取得した場合、まずプレーヤーが現在再生中かどうかを問い合わせてから、答えに応じて状態を切り替える必要があります。これは、stop()
メソッドを呼び出してそれを実行するよりもはるかに面倒です。
playToggle
は非常に面倒です。しかし、代わりにユーザーにトグルボタンも与えられたplayToggle
場合、再生/停止よりも使いやすいでしょう。