フロー制御に例外を使用することで人々が大きな問題を起こすことは知っていますが、それがここでの最大の問題ではありません。巨大なコマンドクエリ分離違反が見つかりました。しかし、それは最悪ではありません。
いいえ、最悪はここです。
/**
* Closes the door if open
*/
ドアの状態についてのあなたの仮定が間違っているがlock()
、あなたのためにそれを修正するだけなのに、なぜ他のすべてが爆破するのですか?これはドアを開けるのをロックすることを不可能にすることを忘れてください、それは絶対に可能で、時々役に立ちます。ここでは問題はありません。間違った仮定に対処するために2つの異なる哲学を混在させていることです。それは紛らわしいです。それをしないでください。同じ命名スタイルで同じレベルの抽象化ではありません。わぁ!それらのアイデアの1つを外に持ち出してください。ドアサービスメソッドはすべて同じように動作するはずです。
コマンドクエリの分離違反に関しては、ドアが閉じているか開いているかを確認するためにドアを閉める必要はありません。私はただ尋ねることができるはずです。ドアサービスは、ドアの状態を変更せずにそれを行う方法を提供していません。これは、値を返すコマンド(CQSが何であるかについてよくある誤解)に比べて、これをはるかに悪化させます。ここでは、状態変更コマンドがクエリを実行する唯一の方法です。わぁ!
例外はステータスコードよりもコストが高いので、それは最適化の話です。十分な速さで十分です。本当の問題は、人間が典型的なケースの例外を期待しないことです。あなたが好きなすべての典型的なものについて議論することができます。私にとって大きな問題は、使用するコードをどの程度読みやすくするかです。
ensureClosed(DoorService service, Door door){
// Need door closed and unlocked. No idea of its state. What to do?
try {
service.open(door)
service.close(door)
}
catch( DoorLockedException e ){
//Have no way to unlock the door so give up and die
log(e);
throw new NoOneGaveMeAKeyException(e);
}
catch( DoorAlreadyOpenedException e ){
try {
service.close(door);
}
catch( DoorAlreadyClosedException e ){
//Some multithreaded goof has been messing with our door.
//Oh well, this is what we wanted anyway.
//Hope they didn't lock it.
}
}
}
このようなコードを書かないでください。方法isLocked()
など教えてくださいisClosed()
。それらを使用して、自分ensureClosed()
でensureUnlocked()
読みやすいメソッドを作成できます。投稿条件に違反した場合にのみスローするもの。もちろん、あなたがすでにそれらを書いてテストしたことがあると思います。状態を変更できないときにスローするものと一緒に混ぜないでください。少なくとも、区別しやすい名前を付けてください。
何をするにしても、何も呼ばないでくださいtryClose()
。それはひどい名前です。
用としてDoorLockedException
も持つ対だけでDoorAlreadyLockedException
病気がこれを言う:それは使用してコードについてのすべてです。使用するコードを記述し、作成している混乱を確認せずに、このようなサービスを設計しないでください。使用するコードが少なくとも読めるようになるまで、リファクタリングと再設計を行います。実際、使用コードを最初に記述することを検討してください。
ensureClosed(DoorService service, Door door){
if( !service.isClosed(door) ){
try{
service.close(door);
}
catch( DoorAlreadyClosedException e ){
//Some multithreaded goof has been messing with our door.
//Oh well, this is what we wanted anyway.
//Hope they didn't lock it.
}
} else {
//This is what you wanted, so quietly do nothing.
//Why are you even here? Who bothers to write empty else conditions?
}
}
ensureUnlocked(DoorService service, Door door){
if( service.islocked(door) ){
throw new NoOneGaveMeAKeyException();
}
}