S-Principleを尊重するクラス内で例外処理をどのように使用すればよいのか混乱しています。
たとえば、C#で次のコードを考えます。
public class BcryptDecrypt
{
private string _password;
private string _hash;
public BcryptDecrypt(string password, string hash)
{
this._password = password;
this._hash = hash;
}
public bool Verify()
{
return BCrypt.Net.BCrypt.Verify(this._password, this._hash);
}
}
明らかにそれはbcryptハッシュを復号化すると述べています。しかし、Verify
メソッドには、例外を処理するtry-catchブロックがないことがわかります。
例外を処理するためにtry-catchを追加すると、S原則に従うことができなくなります。では、ソフトウェアエンジニアはこの問題をどのように解決するのでしょうか。
// After adding try-catch
public class BcryptDecrypt
{
private string _password;
private string _hash;
public BcryptDecrypt(string password, string hash)
{
this._password = password;
this._hash = hash;
}
public bool Verify()
{
try
{
return BCrypt.Net.BCrypt.Verify(this._toDecrypt,
this._hash);
}
catch (System.Exception SomeException)
{
// Handle exception as you like and break S-Principle
}
}
}
私が考えた1つの方法は、各メソッドまたはクラスの例外を処理する個別のクラスを作成するか、それを処理するユニバーサルクラスを作成することです。
Stack Overflow についても同様の質問がありましたが、唯一の回答は、例外を再度スローしてコントローラーに処理させることでした。これは、コントローラー自体がS原則に従っていることを考えると、私にとっては解決策のようには思えません。
SRPに関する根本的な誤解がここにあります:
単一の責任は、クラスが1つのことだけを実行する必要があることを意味しませんが、変更する理由は1つだけであることを意味します。
言い換えれば、それはクラスの単一の責任ではなく、クラスが変更する単一の責任です。つまり、意思決定についてです。
その結果、そのクラスで例外処理をうまく行うことができ、設計上の懸念はありません。本当に必要な場合は、暗号化、復号化、および自動チェックのための単一のCypher
クラスを使用することもできます。
クリーンコードでは、ボブおじさんはDo-one-thing-and-do-it-wellも関数に昇格させます。これは例外処理のために疑われる可能性があります:
したがって、オプション2は受け入れられます。
関数について考慮すべき残りの原則は、単一レベルの抽象化の原則 ( [〜#〜] slap [〜#〜] です。 ):
try
を使用する場合は、catch
を実行して高レベルの関数を実行する必要があります。例外処理が複雑になりすぎた場合は、ここで実用的な アドバイス :
Tryとcatchの本体を抽出して、独自の機能にブロックすることをお勧めします。
スローされた直後に例外をキャッチしないでください。例外を見つけて、それらを使って意味のあることができるようにします。
しかし、サンプルコードはthereをスローするべきではありません。唯一の妥当な例外はArgumentNullException
で、これはyouがコンストラクタでスローする必要があります。
public class BcryptDecrypt
{
private string _password;
private string _hash;
public BcryptDecrypt(string password, string hash)
{
Ensure.ArgumentNotNull(password, nameof(password));
Ensure.ArgumentNotNull(hash, nameof(hash));
this._password = password;
this._hash = hash;
}
public bool Verify()
{
return BCrypt.Net.BCrypt.Verify(this._password, this._hash);
}
}
単一責任原則を理解していませんでした。
つまり、1つのことを実行する-完全に。それを動作させるために必要なすべてのもので。例外処理のように。例外処理のために別のクラスを追加するのはまったくとんでもないことです。
ロブスターを調理するシェフは、鍋に水を入れ、オーブンに入れ、火をつけ、水が沸騰するまで待ち、ロブスターを投入します。 SRPはnotは、PotTakerClass、PotWithWaterFillerClass、PotOnOvenPutterClass、および他の数十のクラスが必要であると言います。
SRPは、LobsterCookerClassが必要だとさえ言っていません。必要なのは、食品を調理する単一の責任を持つ1つのChefClassだけです。 PS。良いシェフは神のようなものであり、それは何も悪いことではありません。
他の人が言ったように、あなたはSRPを誤解しているかもしれません。 SRPは明確に定義されていません。あなたはそれを無視して、 Coupling and Cohesion や Law of Demeter のようなより明確に定義された他の原則に集中する方がよいでしょう。
私はそれについてコメントするためにここに本当にいるのではなく、あなたのデザインについてです。あなたは言う:
明らかにそれはbcryptハッシュを復号化すると述べています。
それはそれがが何をするかを述べるべきではなく、それがは何であるかです。オブジェクトは手続きではなく物です。つまり、「BcryptHash」です。そしておそらくそれは文字列がそれにハッシュするかどうかを検証するべきです。何かのようなもの:
public class BrcyptHash {
private string _hash;
...
public bool IsOf(string text)
...