Come gestire una singola responsabilità quando la responsabilità è condivisa?

10

Ho due classi base, Operation e Trigger . Ognuno ha un numero di sottoclassi che si specializzano in determinati tipi di operazioni o trigger. Un Trigger può attivare uno specifico Operation . Mentre Operation può essere attivato da uno specifico Trigger .

Ho bisogno di scrivere il codice che associa un dato Operation a un dato Trigger (o viceversa), ma non sono sicuro di dove metterlo.

In questo caso il codice non appartiene chiaramente a una classe o all'altra classe. Quindi, in termini di un principio di responsabilità singola, non sono sicuro di dove debba appartenere il codice.

Posso vedere tre opzioni che funzionerebbero tutte. Mentre 1 & 2 sembrano essere solo una scelta di semantica, 3 rappresenta un approccio completamente diverso.

  1. Sul trigger, ad es. %codice%.
  2. sull'operazione, ad es. %codice%.
  3. In una classe completamente nuova che gestisce la mappatura, ad es. bool Triggers(Operation o) .

Come dovrei decidere dove posizionare il codice di mappatura condivisa rispetto a un singolo principio di responsabilità?

Come gestire una singola responsabilità quando la responsabilità è condivisa?

Modifica 1.

Quindi il codice attuale è simile a questo. Tutte le proprietà sono o bool TriggeredBy(Trigger t) , bool MappingExists(Trigger t, Operation o) , string o Guid . In pratica rappresentano solo piccole porzioni di dati.

Modifica 2.

Il motivo per il tipo di ritorno di bool. Un'altra classe sta per consumare una raccolta di collection<string> e una raccolta di enum . È necessario sapere dove esiste una mappatura tra Trigger e Operation . Utilizzerà tali informazioni per creare un rapporto.

    
posta James Wood 16.02.2016 - 20:33
fonte

3 risposte

4

Ci penserei in questo modo: come viene determinato quale Operazione determina quale Trigger deve essere attivato. Deve essere un algoritmo che può cambiare nel tempo o evolvere in più algoritmi. Inserirlo in una delle classi Trigger o Operazione implica che tali classi saranno in grado di gestire tali scenari in futuro. Nota che non la vedo così semplice come una mappatura dal momento che potrebbe esserci di più.

La mia scelta sarebbe quella di creare una classe con metodi appropriati, come GetOperationForTrigger (Trigger t). Ciò consente al codice di evolvere in un insieme di tali classi la cui scelta può dipendere dal runtime o da altre variabili (ad es. Pattern di strategia).

Si noti che l'assunto principale in questa linea di pensiero è scrivere un codice minimale (cioè tre classi oggi) ma evitare un grande refactoring se la funzionalità deve essere estesa in futuro non facendo presupporre che ci sarà sempre esattamente un modo per determinare quale Trigger determina quale Operazione.

Spero che questo aiuti. Sebbene la risposta sia simile a user61852, il ragionamento è diverso. Di conseguenza, l'implementazione sarà diversa (ovvero, i metodi espliciti anziché eseguire l'override degli equals, quindi il numero di metodi può evolvere nel tempo in base alle esigenze).

    
risposta data 17.02.2016 - 05:23
fonte
5

Ci sono stato, fatto.

Opzione # 3.

Non so quale lingua userete, ma userò uno pseudo-codice che è molto simile a Java. Se la tua lingua è C # probabilmente hai interfacce e strutture simili.

Avere una classe o un'interfaccia Mapping:

public interface Mapping {
    public void setObject1(Object o);
    public void setObject2(Object o);
    public Object getObjecto1();
    public Object getObjecto2();
}
  • Sostituisci il metodo equals() di Mapping in modo che le raccolte di Mapping possano essere chieste se contengono una determinata mappatura.
  • Anche gli oggetti speciali dovrebbero avere metodi equals() .
  • Implementa anche l'interfaccia Comparable , quindi puoi ordinare i rapporti.

Li puoi semplicemente mettere una mappatura in una collezione

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

Più tardi puoi chiedere:

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

if ( list.contains(x) ){
    // do some thing
}
    
risposta data 16.02.2016 - 22:04
fonte
0
  1. Rompi il tuo codice in parti più piccole.

Attualmente hai una classe A che conosce la classe B e la classe B che sa della classe A. Questo è un sacco di accoppiamenti in corso.

Per definizione A sta facendo almeno la propria operazione AND controllando se B dovrebbe essere eseguito. Il contrario è vero con B. Qualunque classe la abbia chiamata per prima cosa dovrebbe essere in grado di guardare il risultato e vedere se è necessario eseguire ulteriori operazioni.

Prova a interrompere questo abbinamento dividendo le tue classi in componenti più piccoli. Mi piace mettere un commento in cima a ogni classe spiegando in inglese semplice cosa fa. Se hai bisogno di usare parole come AND o se va oltre una frase o due, allora devi prendere in considerazione la possibilità di scomporlo. Come regola generale qualsiasi cosa dopo un "e" dovrebbe essere nella sua classe

Controlla anche se è possibile definire un'interfaccia che copra le funzionalità di Trigger e Operazione. Se non sai che è un'altra indicazione che la tua classe sta diventando troppo grande. Romperà anche l'accoppiamento tra le tue classi.

    
risposta data 16.02.2016 - 20:59
fonte

Leggi altre domande sui tag