J'ai travaillé avec des exemples comme un objet Player qui sait changer son propre état.
Un autre exemple est un objet Facture qui savait calculer ses frais de facturation à l'aide d'un algorithme.
Cela viole-t-il le principe de responsabilité unique?
Si oui, la création d'un InvoiceCalculator est-elle la bonne approche pour héberger l'algorithme?
Et le PlayerStateChanger est une chose valide.
Je suis arrivé à la conclusion que le "principe de responsabilité unique" fait plus de mal que de bien en raison de son nom déroutant.
Le principe dit pas qu'une classe ne devrait être autorisée qu'à faire une seule chose spécifique. Si tel était le cas, ce serait un principe vraiment stupide!
Un objet sachant comment changer son état est parfaitement bien - en effet, beaucoup diront que seulement l'objet lui-même devrait pouvoir changer son état. Un objet de facture capable de calculer les frais de facturation semble également très bien.
Le PRS consiste à séparer les préoccupations qui pourraient changer indépendamment. Un objet de facture qui contient une logique de rendu comme PDF et logique de calcul des frais enfreindrait le principe, car l'apparence et la présentation de la facture peuvent changer indépendamment de l'algorithme de calcul des frais.
(Notez que "changer" fait référence ici à des changements dans les exigences qui obligent les développeurs à modifier le code, pas aux changements d'état d'exécution qui est un problème distinct.)
Le SRP peut nous conduire à définir de nombreuses petites classes juste pour être sûr de la séparation. Mais le principe doit être mis en balance avec son homologue, que les choses qui changent à l'unisson devraient être couplé dans le code. C'est ce qu'on appelle un "couplage faible mais une cohésion élevée".
Je déconseille de concevoir des objets de données (objets de domaine) qui peuvent changer eux-mêmes.
Je préfère faire la distinction suivante:
Player
, Invoice
. De préférence immuable, mais dépend de l'application (par exemple, pour un jeu, vous devrez peut-être avoir des objets mutables pour plus d'efficacité)InvoiceCalculator
ou Bank
objet qui dépose de l'argent dans Account
sAvantages:
Ce que je décris ci-dessus a été qualifié de modèle de domaine anémique , par Martin Fowler. Je préfère l'appeler séparation des préoccupations .
N'oubliez pas que la programmation n'est pas un dogme, alors ne vous découragez pas pour ceux qui pourraient dire "ce n'est pas vrai OOP". OOP n'est qu'un paradigme - il y a aussi les procédures et les fonctions.
Lorsque l'article a été rédigé en 2003, les programmes multicœurs n'étaient pas aussi courants qu'aujourd'hui. De nos jours, ils le sont, donc j'aime garder mes objets de données simples et immuables et gérer la logique ailleurs.
Un logiciel a de nombreuses parties prenantes et chacune de ces parties prenantes peut demander des modifications.
Par exemple, une application de facturation a plusieurs parties prenantes:
Le principe de responsabilité unique a pour but de vous aider à freiner quelque chose de la partie prenante B lorsque vous effectuez un changement demandé par la partie prenante A. La responsabilité unique signifie que chaque classe doit être responsable devant une seule personne (ou mieux, un rôle) dans l'entreprise.
La dernière chose que vous voulez faire, c'est que le COO vous crie pour casser le calcul de la taxe, tout en migrant vers un autre schéma de base de données ou en modifiant la présentation du rapport que le comptable vous a demandé.
Maintenant, spécifiquement pour le cas de la facture dans votre exemple, le modèle BCE vous recommande de faire une distinction entre la logique indépendante de l'application et la logique spécifique à l'application. Une facture est un objet métier (alias domaine). Cet objet pourrait aussi bien être utilisé par d'autres applications au sein de l'entreprise qui ont à voir avec les factures. Des méthodes telles que addItem (), removeItem () appartiennent à la classe de facture (qui est un objet métier) car elles sont indépendantes du cas d'utilisation. Maintenant, le code en ce qui concerne certains cas d'utilisation spécifiques, appartient à une autre classe connue sous le nom de contrôleur (ou interacteur). Je dirais que le calcul des frais fait partie du cas d'utilisation de la facturation et le mettrait probablement séparément. Cela est subjectif, car on peut également affirmer que ces règles ne sont pas spécifiques à cette application ou à ce cas d'utilisation.