it-swarm.com.de

Wie kann man das Prinzip der Einzelverantwortung respektieren und gleichzeitig die Ausnahmebehandlung anwenden?

Ich bin verwirrt darüber, wie genau ich die Ausnahmebehandlung in einer Klasse verwenden soll, die das S-Prinzip respektiert.

Betrachten Sie diesen Code beispielsweise in 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);
    }    
}

Es wird eindeutig angegeben, dass ein bcrypt-Hash entschlüsselt wird. Sie können jedoch in der Methode Verify sehen, dass es keinen Try-Catch-Block gibt, um eine Ausnahme zu behandeln.

Wenn wir einen Try-Catch hinzufügen, um eine Ausnahme zu behandeln, können wir dem S-Prinzip nicht folgen. Wie lösen Softwareentwickler dieses Problem?

// 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
        }
    }    
}

Eine Möglichkeit, die ich mir vorgestellt habe, besteht darin, eine separate Klasse zu erstellen, um jede Methode oder Klassenausnahme zu behandeln, oder eine universelle Klasse zu erstellen, um sie zu behandeln.

Ich habe eine ähnliche Frage zu Stapelüberlauf gesehen, aber die einzige Antwort lautete, dass die Ausnahme erneut ausgelöst werden soll, damit der Controller damit umgehen kann. Dies klingt für mich nicht nach einer Lösung, wenn man bedenkt, dass der Controller selbst dem S-Prinzip folgt.

6
Suleman

Einzelverantwortung?

Hier gibt es ein grundlegendes Missverständnis über SRP:

  • Die Einzelverantwortung bedeutet nicht, dass eine Klasse nur eines tun sollte, sondern nur einen Grund zur Änderung haben sollte.

  • Mit anderen Worten, es ist nicht die alleinige Verantwortung der Klasse, sondern die alleinige Verantwortung, dass sich die Klasse ändert. Es geht also um Entscheidungsfindung.

  • Hier ein aufschlussreicher Artikel von Onkel Bob , der SOLID erfunden hat und es mit all seiner Autorität zu diesem Thema besser erklärt als ich.

Infolgedessen können Sie die Ausnahmebehandlung in dieser Klasse sehr wohl ohne Designprobleme durchführen. Sie könnten sogar eine einzige Cypher -Klasse haben, um sich selbst zu verschlüsseln, zu entschlüsseln und automatisch zu überprüfen, wenn Sie es wirklich wollen.

Eine Sache machen ?

In Clean Code bewirbt Onkel Bob auch das Do-one-thing-and-do-it-well für Funktionen. Dies könnte für die Ausnahmebehandlung in Frage gestellt werden:

  • Mach eine Sache ist nicht dasselbe wie die Hälfte der Sache
  • Wenn etwas Schlimmes passiert, wenn Sie das Ding machen, und wenn Sie nicht so damit umgehen würden, wie Sie sollten, dann würden Sie das Ding nicht gut machen.
  • Die Ausnahmebehandlung verstößt also nicht gegen eine Sache.

Ihre Option 2 ist daher akzeptabel.

Irgendwas mit Try/Catch?

Das einzige verbleibende Prinzip, das für Ihre Funktion berücksichtigt werden muss, ist Prinzip der einzelnen Abstraktionsstufe ( SCHLAG ) :

  • wenn Sie try auf einer übergeordneten Funktion verwenden, sollten Sie catch und eine übergeordnete Funktion ausführen.
  • Es wäre nicht vernünftig, eine catch-Klausel zu haben, die sehr niedrig und detailliert wäre, wie zwei Seiten Code für den catch gegen 1 Zeile für den Versuch.

Wenn die Ausnahmebehandlung zu komplex wird, hier eine nette pragmatische Beratung :

Es ist besser, die Körper des Versuchs zu extrahieren und Blöcke in eigene Funktionen aufzufangen.

13
Christophe

Fang keine Ausnahmen, sobald sie geworfen werden. Fangen Sie Ausnahmen an dem Punkt ab, an dem Sie mit ihnen etwas Sinnvolles tun können.

Ihr Beispielcode sollte dort jedoch nicht werfen . Die einzige vernünftige Ausnahme ist ArgumentNullException, die Sie in den Konstruktor werfen sollten.

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 von hier .

10
Caleth

Sie haben das Prinzip der Einzelverantwortung nicht verstanden.

Es bedeutet: Machen Sie eine Sache - vollständig. Mit allem, was nötig ist, damit es funktioniert. Wie Ausnahmebehandlung. Das Hinzufügen einer weiteren Klasse für die Ausnahmebehandlung wäre absolut lächerlich.

Ein Koch, der einen Hummer kocht, nimmt einen Topf, füllt ihn mit Wasser, stellt ihn auf den Ofen, schaltet die Heizung ein, wartet, bis das Wasser kocht, wirft den Hummer hinein und so weiter. SRP sagt nicht, dass Sie eine PotTakerClass, eine PotWithWaterFillerClass, eine PotOnOvenPutterClass und ein weiteres Dutzend Klassen benötigen.

SRP sagt nicht einmal, dass Sie eine LobsterCookerClass benötigen. Sie benötigen lediglich eine ChefClass mit der alleinigen Verantwortung für das Kochen von Speisen. PS. Ein guter Koch ist wie Gott, und daran ist nichts auszusetzen.

4
gnasher729

Wie andere gesagt haben, verstehen Sie SRP möglicherweise falsch. Fühlen Sie sich nicht schlecht, SRP ist nicht gut definiert. Sie sollten es besser ignorieren und sich auf andere klarere Prinzipien wie Kopplung und Zusammenhalt und Gesetz des Demeters konzentrieren.

Ich bin nicht wirklich hier, um dies zu kommentieren, sondern um Ihr Design. Du sagst:

Es wird eindeutig angegeben, dass ein bcrypt-Hash entschlüsselt wird.

Es sollte nicht angeben, was es tut , sondern was es ist . Objekte sind Dinge, keine Prozeduren. Also, was es sein sollte, ist "BcryptHash". Und es sollte wahrscheinlich überprüfen, ob eine Zeichenfolge darin gehasht wird. Etwas wie:

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