Le principe de ségrégation d'interface dit:
Aucun client ne doit être contraint de dépendre de méthodes qu'il n'utilise pas. Le FAI divise les interfaces très grandes en interfaces plus petites et plus spécifiques afin que les clients n'aient à connaître que les méthodes qui les intéressent.
Il y a quelques questions sans réponse ici. L'un est:
Comme c'est petit?
Vous dites:
Actuellement, je traite cela en divisant l'espace de noms du module en fonction des besoins de ses clients.
J'appelle cette saisie manuelle de canard . Vous créez des interfaces qui exposent uniquement les besoins d'un client. Le principe de ségrégation d'interface n'est pas simplement une saisie manuelle de canard.
Mais le FAI n'est pas simplement un appel à des interfaces de rôle "cohérentes" qui peuvent être réutilisées. Aucune conception d'interface de rôle "cohérente" ne peut parfaitement se prémunir contre l'ajout d'un nouveau client avec ses propres besoins de rôle.
Le FAI est un moyen d'isoler les clients de l'impact des modifications apportées au service. Il était destiné à accélérer la génération lorsque vous apportez des modifications. Bien sûr, cela a d'autres avantages, comme ne pas casser les clients, mais c'était le point principal. Si je modifie la count()
signature de la fonction services , c'est bien si les clients qui n'utilisent pas count()
n'ont pas besoin d'être modifiés et recompilés.
C'est pourquoi je me soucie du principe de ségrégation d'interface. Ce n'est pas quelque chose que je considère comme important. Cela résout un vrai problème.
Ainsi, la façon dont il doit être appliqué devrait résoudre un problème pour vous. Il n'y a pas de moyen par cœur mort pour appliquer un FAI qui ne peut pas être vaincu avec juste le bon exemple de changement nécessaire. Vous êtes censé voir comment le système évolue et faire des choix qui calmeront les choses. Explorons les options.
Demandez-vous d'abord: est-il difficile de modifier l'interface de service en ce moment? Sinon, allez dehors et jouez jusqu'à ce que vous vous calmiez. Ce n'est pas un exercice intellectuel. Veuillez vous assurer que le remède n'est pas pire que la maladie.
Si de nombreux clients utilisent le même sous-ensemble de fonctions, cela plaide pour des interfaces réutilisables "cohérentes". Le sous-ensemble se concentre probablement autour d'une idée que nous pouvons considérer comme le rôle que le service fournit au client. C'est sympa quand ça marche. Cela ne fonctionne pas toujours.
Si de nombreux clients utilisent différents sous-ensembles de fonctions, il est possible que le client utilise réellement le service via plusieurs rôles. C'est OK mais cela rend les rôles difficiles à voir. Trouvez-les et essayez de les taquiner. Cela peut nous remettre dans le cas 1. Le client utilise simplement le service via plusieurs interfaces. Veuillez ne pas commencer à diffuser le service. Si quoi que ce soit, cela signifierait passer le service au client plus d'une fois. Cela fonctionne mais cela me fait me demander si le service n'est pas une grosse boule de boue qui doit être brisée.
Si de nombreux clients utilisent des sous-ensembles différents mais que vous ne voyez même pas de rôles autorisant les clients à en utiliser plusieurs, vous n'avez rien de mieux que de taper du canard pour concevoir vos interfaces. Cette façon de concevoir les interfaces garantit que le client n'est pas exposé à une seule fonction qu'il n'utilise pas, mais il garantit presque que l'ajout d'un nouveau client impliquera toujours l'ajout d'une nouvelle interface qui, même si la mise en œuvre du service n'a pas besoin de savoir à ce sujet l'interface qui agrège les interfaces de rôle sera. Nous avons simplement échangé une douleur contre une autre.
Si de nombreux clients utilisent des sous-ensembles différents, se chevauchent, de nouveaux clients devraient s'ajouter qui auront besoin de sous-ensembles imprévisibles, et vous ne souhaitez pas interrompre le service, alors envisagez une solution plus fonctionnelle. Étant donné que les deux premières options n'ont pas fonctionné et que vous êtes vraiment dans un mauvais endroit où rien ne suit un modèle et que d'autres changements arrivent, envisagez de fournir à chaque fonction sa propre interface. Terminer ici ne signifie pas que le FAI a échoué. Si quelque chose échouait, c'était le paradigme orienté objet. Les interfaces à méthode unique suivent l'extrême FAI. C'est un peu de frappe au clavier, mais vous pouvez trouver que cela rend soudainement les interfaces réutilisables. Encore une fois, assurez-vous qu'il n'y a pas
Il s'avère donc qu'ils peuvent devenir très petits.
J'ai pris cette question comme un défi pour appliquer le FAI dans les cas les plus extrêmes. Mais gardez à l'esprit qu'il vaut mieux éviter les extrêmes. Dans une conception bien pensée qui applique d'autres principes SOLIDES, ces problèmes ne se produisent généralement pas ou importent presque autant.
Une autre question sans réponse est:
À qui appartiennent ces interfaces?
Je vois encore et encore des interfaces conçues avec ce que j'appelle une mentalité de «bibliothèque». Nous avons tous été coupables du codage singe-voir-singe-faire où vous faites juste quelque chose parce que c'est ainsi que vous l'avez vu. Nous sommes coupables de la même chose avec les interfaces.
Quand je regarde une interface conçue pour une classe dans une bibliothèque, je pensais: oh, ces gars sont des pros. Ce doit être la bonne façon de faire une interface. Ce que je n'arrivais pas à comprendre, c'est qu'une limite de bibliothèque a ses propres besoins et problèmes. D'une part, une bibliothèque ignore complètement la conception de ses clients. Toutes les frontières ne sont pas identiques. Et parfois, même la même frontière a différentes façons de la traverser.
Voici deux façons simples d'examiner la conception d'interface:
Interface appartenant au service. Certaines personnes conçoivent chaque interface pour exposer tout ce qu'un service peut faire. Vous pouvez même trouver des options de refactoring dans les IDE qui écriront une interface pour vous en utilisant la classe que vous l'alimenterez.
Interface appartenant au client. Le FAI semble affirmer que c'est juste et que le service appartenant est faux. Vous devez briser chaque interface en fonction des besoins des clients. Puisque le client possède l'interface, il doit la définir.
Alors qui a raison?
Considérez les plugins:
À qui appartiennent les interfaces ici? Les clients? Les services?
S'avère à la fois.
Les couleurs ici sont des couches. Le calque rouge (à droite) n'est pas censé rien savoir du calque vert (à gauche). La couche verte peut être modifiée ou remplacée sans toucher la couche rouge. De cette façon, n'importe quelle couche verte peut être connectée à la couche rouge.
J'aime savoir ce qui est censé savoir quoi et ce qui n'est pas censé savoir. Pour moi, "qu'est-ce qui sait quoi?", Est la question architecturale la plus importante.
Rendons le vocabulaire clair:
[Client] --> [Interface] <|-- [Service]
----- Flow ----- of ----- control ---->
Un client est quelque chose qui utilise.
Un service est quelque chose qui est utilisé.
Interactor
se trouve être les deux.
Le FAI dit de briser les interfaces pour les clients. Très bien, appliquons cela ici:
Presenter
(un service) ne doit pas dicter à l' Output Port <I>
interface. L'interface doit être limitée à ce dont Interactor
(ici, en tant que client) a besoin. Cela signifie que l'interface CONNAIT le Interactor
et, pour suivre le FAI, doit changer avec lui. Et c'est très bien.
Interactor
(ici en tant que service) ne doit pas dicter à l' Input Port <I>
interface. L'interface doit être limitée aux Controller
besoins (d'un client). Cela signifie que l'interface CONNAIT le Controller
et, pour suivre le FAI, doit changer avec lui. Et ce n'est pas bien.
Le second n'est pas bien car la couche rouge n'est pas censée connaître la couche verte. Le FAI a-t-il donc tort? Enfin un peu. Aucun principe n'est absolu. Il s'agit d'un cas où les gaffes qui aiment que l'interface montre tout ce que le service peut faire se révèlent corrects.
Au moins, ils ont raison si le Interactor
ne fait rien d'autre que ce dont le cas d'utilisation a besoin. Si le Interactor
fait des choses pour d'autres cas d'utilisation, il n'y a aucune raison que cela les Input Port <I>
connaisse. Je ne sais pas pourquoi Interactor
ne peut pas se concentrer uniquement sur un cas d'utilisation, donc ce n'est pas un problème, mais des choses se produisent.
Mais l' input port <I>
interface ne peut tout simplement pas s'asservir au Controller
client et avoir un véritable plugin. Il s'agit d'une limite de «bibliothèque». Un magasin de programmation complètement différent pourrait écrire la couche verte des années après la publication de la couche rouge.
Si vous traversez une frontière de `` bibliothèque '' et que vous ressentez le besoin d'appliquer ISP même si vous ne possédez pas l'interface de l'autre côté, vous devrez trouver un moyen de restreindre l'interface sans la changer.
Un moyen de retirer cela est un adaptateur. Mettez-le entre les clients comme Controler
et l' Input Port <I>
interface. L'adaptateur accepte en Interactor
tant que Input Port <I>
et délègue son travail à lui. Cependant, il expose uniquement les Controller
besoins des clients via une ou plusieurs interfaces de rôle appartenant à la couche verte. L'adaptateur ne suit pas le FAI lui-même mais permet à une classe plus complexe Controller
de profiter du FAI. Cela est utile s'il y a moins d'adaptateurs que les clients Controller
qui les utilisent et lorsque vous vous trouvez dans une situation inhabituelle où vous traversez les limites d'une bibliothèque et, malgré sa publication, la bibliothèque ne cessera de changer. En vous regardant Firefox. Maintenant, ces changements ne font que casser vos adaptateurs.
Qu'est-ce que cela signifie? Cela signifie honnêtement que vous n'avez pas fourni suffisamment d'informations pour que je puisse vous dire ce que vous devez faire. Je ne sais pas si le fait de ne pas suivre le FAI vous pose un problème. Je ne sais pas si le suivre ne finirait pas par vous causer plus de problèmes.
Je sais que vous cherchez un principe directeur simple. Le FAI essaie d'être ça. Mais cela laisse beaucoup de choses à dire. J'y crois. Oui, veuillez ne pas forcer les clients à dépendre de méthodes qu'ils n'utilisent pas, sans bonne raison!
Si vous avez une bonne raison, telle que la conception de quelque chose pour accepter les plugins, alors soyez conscient des problèmes qui ne suivent pas les causes des FAI (il est difficile de changer sans casser les clients) et des moyens de les atténuer (garder Interactor
ou au moins se Input Port <I>
concentrer sur une seule écurie) cas d'utilisation).