J'écris beaucoup de code qui implique trois étapes de base.
- Obtenez des données quelque part.
- Transformez ces données.
- Mettez ces données quelque part.
Je finis généralement par utiliser trois types de classes - inspirées de leurs modèles de conception respectifs.
- Usines - pour construire un objet à partir d'une ressource.
- Médiateurs - pour utiliser l'usine, effectuer la transformation, puis utiliser le commandant.
- Commandants - pour mettre ces données ailleurs.
Mes classes ont tendance à être assez petites, souvent une seule méthode (publique), par exemple obtenir des données, transformer des données, travailler, enregistrer des données. Cela conduit à une prolifération de classes, mais fonctionne généralement bien.
Là où je me bats, c'est quand je viens aux tests, je me retrouve avec des tests étroitement couplés. Par exemple;
- Usine - lit les fichiers du disque.
- Commander - écrit des fichiers sur le disque.
Je ne peux pas tester l'un sans l'autre. Je pourrais écrire du code «test» supplémentaire pour lire / écrire sur le disque également, mais je me répète.
En regardant .Net, la classe File adopte une approche différente, elle combine les responsabilités (de mon) usine et commandant ensemble. Il a des fonctions pour créer, supprimer, existe et tout lire en un seul endroit.
Dois-je chercher à suivre l'exemple de .Net et combiner - en particulier lorsqu'il s'agit de ressources externes - mes classes ensemble? Le code est toujours couplé, mais il est plus intentionnel - il se produit lors de l'implémentation d'origine, plutôt que dans les tests.
Est-ce que mon problème ici est que j'ai appliqué le principe de responsabilité unique de manière un peu trop zélée? J'ai des classes distinctes responsables de la lecture et de l'écriture. Quand je pourrais avoir une classe combinée chargée de gérer une ressource particulière, par exemple le disque système.
Looking at .Net, the File class takes a different approach, it combines the responsibilities (of my) factory and commander together. It has functions for Create, Delete, Exists, and Read all in one place.
- Notez que vous confondez «responsabilité» avec «chose à faire». Une responsabilité ressemble plus à un «domaine de préoccupation». La responsabilité de la classe File consiste à effectuer des opérations sur les fichiers.
File
bibliothèque de C # est, pour tout ce que nous savons, la File
classe pourrait simplement être une façade, mettant toutes les opérations sur les fichiers en un seul endroit - dans la classe, mais pourrait utiliser en interne une classe de lecture / écriture similaire à la vôtre qui contiennent en fait la logique la plus compliquée pour la gestion des fichiers. Une telle classe (la File
) adhérerait toujours au SRP, parce que le processus de travail avec le système de fichiers serait abstrait derrière une autre couche - très probablement avec une interface unificatrice. Je ne dis pas que c'est le cas, mais ça pourrait l'être. :)