Je suis confus sur la façon dont dois-je utiliser la gestion des exceptions dans une classe qui respecte le principe S?.
Par exemple, considérez ce code en 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);
}
}
Il indique clairement qu'il déchiffre un hachage bcrypt. Mais vous pouvez voir dans la méthode Verify
qu'il n'y a pas de bloc try-catch pour gérer une exception.
Si nous ajoutons un try-catch pour gérer l'exception, nous ne pouvons pas suivre le principe S. Alors, comment les ingénieurs logiciels résolvent-ils ce problème?
// 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
}
}
}
J'ai pensé à créer une classe distincte pour gérer chaque méthode ou exception de classe ou créer une classe universelle pour la gérer.
J'ai vu une question similaire sur Stack Overflow , mais la seule réponse donnée a dit de relancer l'exception pour laisser le contrôleur la gérer. Cela ne me semble pas être une solution étant donné que le contrôleur lui-même suivrait le principe S.
Il y a ici un malentendu fondamental à propos de SRP:
La responsabilité unique ne signifie pas qu'une classe ne doit faire qu'une seule chose, mais qu'elle ne doit avoir qu'une seule raison de changer.
En d'autres termes, ce n'est pas la seule responsabilité de la classe, mais la seule responsabilité pour la classe de changer. Il s'agit donc de la prise de décision.
Par conséquent, vous pouvez très bien gérer les exceptions dans cette classe sans aucun problème de conception. Vous pouvez même avoir une seule classe Cypher
pour le chiffrement, le déchiffrement et l'autocheck, si vous le souhaitez vraiment.
Dans Clean Code, Oncle Bob promeut également le Do-one-thing-and-do-it-well , pour les fonctions. Cela pourrait être remis en question pour la gestion des exceptions:
Votre option 2 est donc acceptable.
Le seul principe restant à considérer pour votre fonction est Principe de niveau d'abstraction unique ( SLAP ) :
try
sur une fonction de haut niveau, vous devez catch
et faire une fonction de haut niveau.Si la gestion des exceptions devient trop complexe, voici un Nice pragmatique conseil :
Il est préférable d'extraire les corps de l'essai et de rattraper les blocs dans leurs propres fonctions.
N'attrapez pas d'exceptions dès qu'elles sont levées. Détectez les exceptions au moment où vous pouvez faire quelque chose de significatif avec elles.
Mais votre exemple de code ne devrait pas y lancer . La seule exception raisonnable est ArgumentNullException
, que vous devez jeter dans le constructeur.
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);
}
}
Vous ne compreniez pas le principe de responsabilité unique.
Cela signifie: Faites une chose - complètement. Avec tout ce qui est nécessaire pour le faire fonctionner. Comme la gestion des exceptions. Ajouter une autre classe pour la gestion des exceptions serait tout à fait ridicule.
Un chef cuisinant un homard prend une casserole, la remplit d'eau, la met au four, allume le feu, attend que l'eau bout, jette la langouste, etc. SRP ne pas dit que vous avez besoin d'un PotTakerClass, d'un PotWithWaterFillerClass, d'un PotOnOvenPutterClass et d'une douzaine de classes.
SRP ne dit même pas que vous avez besoin d'une LobsterCookerClass. Tout ce dont vous avez besoin est une ChefClass avec la seule responsabilité de cuisiner les aliments. PS. Un bon chef est comme Dieu, et il n'y a rien de mal à cela.
Comme d'autres l'ont dit, vous pouvez mal comprendre SRP. Ne vous sentez pas mal cependant, SRP n'est pas bien défini. Vous feriez mieux de l'ignorer et de vous concentrer sur d'autres principes plus bien définis comme Couplage et Cohésion et la Loi de Déméter .
Je ne suis pas vraiment ici pour commenter cela, mais à propos de votre conception. Vous dites:
Il indique clairement qu'il déchiffre un hachage bcrypt.
Il ne doit pas indiquer ce qu'il fait , mais ce que c'est . Les objets sont des choses, pas des procédures. Donc, ce que cela devrait être "BcryptHash". Et il devrait probablement vérifier si une chaîne y est hachée. Quelque chose comme:
public class BrcyptHash {
private string _hash;
...
public bool IsOf(string text)
...