web-dev-qa-db-ja.com

単一責任の原則を尊重し、同時に例外処理を使用するにはどうすればよいですか?

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原則に従っていることを考えると、私にとっては解決策のようには思えません。

6
Suleman

単一責任?

SRPに関する根本的な誤解がここにあります:

  • 単一の責任は、クラスが1つのことだけを実行する必要があることを意味しませんが、変更する理由は1つだけであることを意味します。

  • 言い換えれば、それはクラスの単一の責任ではなく、クラスが変更する単一の責任です。つまり、意思決定についてです。

  • ここに、SOLIDを発明した ncle Bobからの啓蒙記事 があり、この件に関して彼の全権威を持つ私よりもそれをよりよく説明しています。

その結果、そのクラスで例外処理をうまく行うことができ、設計上の懸念はありません。本当に必要な場合は、暗号化、復号化、および自動チェックのための単一のCypherクラスを使用することもできます。

何かしますか?

クリーンコードでは、ボブおじさんはDo-one-thing-and-do-it-wellも関数に昇格させます。これは例外処理のために疑われる可能性があります:

  • 1つのことを行うは、半分のことを行うのと同じではありません
  • あなたが物事を行うときに何か悪いことが起こった場合、そしてあなたがそれをあなたがするべきように処理しなければ、あなたはその物事をうまく行うことができません。
  • したがって、例外処理は1つのことを侵害しません。

したがって、オプション2は受け入れられます。

Try/catchについて何かありますか?

関数について考慮すべき残りの原則は、単一レベルの抽象化の原則[〜#〜] slap [〜#〜] です。 )

  • 高レベルの関数でtryを使用する場合は、catchを実行して高レベルの関数を実行する必要があります。
  • Catchの2ページのコードとtryの1行のように、非常に低レベルで詳細なcatch句を使用するのは適切ではありません。

例外処理が複雑になりすぎた場合は、ここで実用的な アドバイス

Tryとcatchの本体を抽出して、独自の機能にブロックすることをお勧めします。

13
Christophe

スローされた直後に例外をキャッチしないでください。例外を見つけて、それらを使って意味のあることができるようにします。

しかし、サンプルコードは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);
    }    
}

Ensure.ArgumentNotNullここから

10
Caleth

単一責任原則を理解していませんでした。

つまり、1つのことを実行する-完全に。それを動作させるために必要なすべてのもので。例外処理のように。例外処理のために別のクラスを追加するのはまったくとんでもないことです。

ロブスターを調理するシェフは、鍋に水を入れ、オーブンに入れ、火をつけ、水が沸騰するまで待ち、ロブスターを投入します。 SRPはnotは、PotTakerClass、PotWithWaterFillerClass、PotOnOvenPutterClass、および他の数十のクラスが必要であると言います。

SRPは、LobsterCookerClassが必要だとさえ言っていません。必要なのは、食品を調理する単一の責任を持つ1つのChefClassだけです。 PS。良いシェフは神のようなものであり、それは何も悪いことではありません。

4
gnasher729

他の人が言ったように、あなたはSRPを誤解しているかもしれません。 SRPは明確に定義されていません。あなたはそれを無視して、 Coupling and CohesionLaw of Demeter のようなより明確に定義された他の原則に集中する方がよいでしょう。

私はそれについてコメントするためにここに本当にいるのではなく、あなたのデザインについてです。あなたは言う:

明らかにそれはbcryptハッシュを復号化すると述べています。

それはそれがが何をするかを述べるべきではなく、それがは何であるかです。オブジェクトは手続きではなく物です。つまり、「BcryptHash」です。そしておそらくそれは文字列がそれにハッシュするかどうかを検証するべきです。何かのようなもの:

public class BrcyptHash {
   private string _hash;
   ...
   public bool IsOf(string text)
      ...
0