Comment gérer la responsabilité unique lorsque la responsabilité est partagée?

10

J'ai base deux classes, Operationet Trigger. Chacun a un certain nombre de sous-classes qui se spécialisent dans certains types d'opérations ou de déclencheurs. Un Triggerpeut déclencher un spécifique Operation. Alors qu'un Operationpeut être déclenché par un spécifique Trigger.

J'ai besoin d'écrire le code qui mappe un donné Operationà un donné Trigger(ou vice versa), mais je ne sais pas où le mettre.

Dans ce cas, le code n'appartient pas clairement à une classe ou à l'autre classe. Donc, en termes de principe de responsabilité unique, je ne sais pas où le code devrait appartenir.

Je peux voir trois options qui fonctionneraient toutes. Alors que 1 et 2 ne semblent être qu'un choix de sémantique, 3 représente une approche complètement différente.

  1. Sur la gâchette, par exemple bool Triggers(Operation o).
  2. Sur l'opération, par exemple bool TriggeredBy(Trigger t).
  3. Dans une classe entièrement nouvelle qui gère le mappage, par exemple bool MappingExists(Trigger t, Operation o).

Comment dois-je décider où placer le code de mappage partagé dans le respect d'un principe de responsabilité unique?

Comment gérer la responsabilité unique lorsque la responsabilité est partagée?


Modifier 1.

Ainsi, le code réel ressemble à ceci. Toutes les propriétés sont soit un string, Guid, collection<string>ou enum. Ils représentent simplement de petites données.

entrez la description de l'image ici

Modifier 2.

La raison du type de retour de bool. Une autre classe va consommer une collection de Triggeret une collection de Operation. Il doit savoir où existe une correspondance entre a Triggeret an Operation. Il utilisera ces informations pour créer un rapport.

James Wood
la source
Pourquoi le type booléen?
Tulains Córdova
@ user61852 pour renvoyer un résultat au code d'appel
James Wood
1
Que fait le code appelant avec le booléen? Selon ce que vous répondez à cette question, je pourrais avoir la solution.
Tulains Córdova
@ user61852, veuillez voir mes modifications.
James Wood
1
Donc, cela n'a rien à voir avec l'exécution effective du déclencheur de l'opération?
Tulains Córdova

Réponses:

4

J'y penserais ainsi: comment détermine-t-on quelle opération provoque le déclenchement de quel déclencheur. Il doit s'agir d'un algorithme qui peut évoluer dans le temps ou évoluer en plusieurs algorithmes. Le placer dans les classes Trigger ou Operation implique que ces classes seront capables de gérer de tels scénarios à l'avenir. Notez que je ne le vois pas aussi simple qu'un mappage car il peut y en avoir plus.

Mon choix serait de créer une classe avec des méthodes appropriées, telles que GetOperationForTrigger (Trigger t). Cela permet au code d'évoluer en un ensemble de ces classes dont le choix peut dépendre au moment de l'exécution ou d'autres variables (par exemple le modèle de stratégie).

Notez que l'hypothèse principale dans cette ligne de pensée est d'écrire du code minimal (c'est-à-dire trois classes aujourd'hui) mais pour éviter une refactorisation majeure si la fonctionnalité doit être étendue à l'avenir en ne faisant pas l'hypothèse qu'il y aura toujours exactement une façon de déterminer quel déclencheur provoque quelle opération.

J'espère que cela t'aides. Bien que la réponse soit similaire à user61852, le raisonnement est différent. Par conséquent, l'implémentation sera différente (c.-à-d. Avoir des méthodes explicites au lieu de remplacer les égales, de sorte que le nombre de méthodes peut évoluer dans le temps en fonction des besoins).

Omer Iqbal
la source
5

J'y suis allé, j'ai fait ça.

Option n ° 3.

Je ne sais pas quelle langue vous utiliserez mais j'utiliserai un pseudo-code très similaire à Java. Si votre langage est C #, vous avez probablement des interfaces et des structures similaires.

Avoir une classe ou une interface de mappage:

public interface Mapping {
    public void setObject1(Object o);
    public void setObject2(Object o);
    public Object getObjecto1();
    public Object getObjecto2();
}
  • Remplacez la equals()méthode de Mappingsorte que les collections de Mappingpeuvent être demandées si elles contiennent un mappage donné.
  • Les objets spécialisés devraient également avoir des equals()méthodes appropriées .
  • Implémentez également l'interface Comparablepour pouvoir trier les rapports.

Vous pouvez simplement mettre un mappage dans une collection

List<Mapping> list = new ArrayList<Mapping>();
Hat hat = new Hat();
Bag bag = new Bag();
list.add(new Mapping(hat,bag));

Plus tard, vous pourrez demander:

// let's say you have a variable named x which is of type Mapping

if ( list.contains(x) ){
    // do some thing
}
Tulains Córdova
la source
0
  1. Décomposez votre code en petits morceaux.

Actuellement, vous avez la classe A connaissant la classe B et la classe B connaissant la classe A. C'est beaucoup de couplage en cours.

Par définition, A effectue au moins sa propre opération ET vérifie si B doit être exécuté. L'inverse est vrai avec B. Quelle que soit la première classe appelée, elle devrait pouvoir regarder le résultat et voir si d'autres choses doivent être exécutées.

Essayez de briser ce couplage en divisant vos classes en composants plus petits. J'aime mettre un commentaire en haut de chaque classe expliquant en anglais ce qu'il fait. Si vous devez utiliser des mots comme ET ou si cela va sur une phrase ou deux, vous devez envisager de le décomposer. En règle générale, tout ce qui suit un "et" doit être dans sa propre classe

Vérifiez également si vous pouvez définir une interface qui couvre les fonctionnalités de déclenchement et d'opération. Si vous ne pouvez pas, c'est une autre indication que votre classe devient trop grande. Cela rompra également le couplage entre vos classes.

Tom Squires
la source
1
En toute honnêteté, je ne suis pas sûr de pouvoir décomposer davantage mon code. J'ai mis à jour ma question avec les signatures de classe pour que vous puissiez voir, mais en gros, ce sont des objets de données assez légers stockant quelques propriétés chacun. En ce qui concerne le couplage, oui, c'est un peu problématique, car effectivement un Triggerserait couplé à un Operation. Mais c'est en quelque sorte à quoi ressemblent les données du monde réel. Ils sont couplés, car il y a une cartographie, par exemple ils doivent se connaître pour avoir un sens.
James Wood