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


10

Ho due classi di base Operatione Trigger. Ognuno ha un numero di sottoclassi specializzate in determinati tipi di operazioni o trigger. A Triggerpuò attivare uno specifico Operation. Mentre un Operationpuò essere attivato da uno specifico Trigger.

Devo scrivere il codice che mappa un dato Operationa un dato Trigger(o viceversa), ma non sono sicuro di dove inserirlo.

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

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

  1. Sul grilletto, ad es bool Triggers(Operation o).
  2. Sull'operazione, ad es bool TriggeredBy(Trigger t).
  3. In una classe completamente nuova che gestisce la mappatura, ad es bool MappingExists(Trigger t, Operation o).

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

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


Modifica 1.

Quindi il codice attuale è simile al seguente. Tutte le proprietà, sono sia un string, Guid, collection<string>, o enum. Fondamentalmente rappresentano solo piccoli pezzi di dati.

inserisci qui la descrizione dell'immagine

Modifica 2.

Il motivo del tipo di ritorno bool. Un'altra classe consumerà una raccolta di Triggere una raccolta di Operation. Deve sapere dove esiste una mappatura tra a Triggere an Operation. Utilizzerà tali informazioni per creare un rapporto.


Perché il tipo bool?
Tulains Córdova,

@ user61852 per restituire un risultato al codice chiamante
James Wood,

1
Cosa fa il codice chiamante con il valore booleano? A seconda di cosa rispondi a questa domanda potrei avere la soluzione.
Tulains Córdova,

@ user61852, per favore vedi le mie modifiche.
James Wood,

1
Quindi non ha nulla a che fare con l'esecuzione del trigger dell'operazione?
Tulains Córdova,

Risposte:


4

Ci penserei in questo modo: come viene determinato quale Operazione provoca l'attivazione del trigger. Deve essere un algoritmo che può cambiare nel tempo o evolversi in più algoritmi. Inserirlo in classi Trigger o Operation implica che tali classi saranno in grado di gestire tali scenari in futuro. Nota che non lo vedo semplice come una mappatura poiché potrebbe essercene di più.

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

Si noti che il presupposto principale in questa linea di pensiero è quello di scrivere un codice minimo (ovvero tre classi oggi) ma di evitare importanti refactoring se la funzionalità deve essere estesa in futuro non assumendo che ci sarà sempre esattamente un modo per determinare quale trigger provoca quale operazione.

Spero che sia di aiuto. Sebbene la risposta sia simile a user61852, il ragionamento è diverso. Di conseguenza, l'implementazione sarà diversa (ovvero hanno metodi espliciti anziché sovrascrivere uguali, quindi il numero di metodi può evolversi nel tempo in base alle esigenze).


5

Ci sono stato, l'ho fatto.

Opzione n. 3.

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

Avere una classe o un'interfaccia di mappatura:

public interface Mapping {
    public void setObject1(Object o);
    public void setObject2(Object o);
    public Object getObjecto1();
    public Object getObjecto2();
}
  • Sostituire il equals()metodo in Mappingmodo che le raccolte di Mappingpossano essere interrogate se contengono un dato mapping.
  • Gli oggetti speciali dovrebbero avere anche equals()metodi specifici.
  • Implementa anche l'interfaccia Comparable, in modo da poter ordinare i report.

Puoi semplicemente mettere una mappatura in una raccolta

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

Successivamente puoi chiedere:

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

if ( list.contains(x) ){
    // do some thing
}

0
  1. Suddividi il codice in bit più piccoli.

Attualmente hai conoscenza della classe A sulla classe B e della classe B sulla classe A. Questo è un sacco di accoppiamento in corso.

Per definizione, A sta eseguendo almeno la propria operazione E verifica se B deve essere eseguito. È vero il contrario con B. Qualunque sia la prima classe chiamata, dovrebbe essere in grado di guardare il risultato e vedere se è necessario eseguire ulteriori operazioni.

Prova a interrompere tale accoppiamento dividendo le tue classi in componenti più piccoli. Mi piace mettere un commento all'inizio di ogni lezione spiegando in parole povere cosa fa. Se hai bisogno di usare parole come AND o supera una o due frasi, devi considerare di scomporle. Come regola generale, qualsiasi cosa dopo un "e" dovrebbe essere nella sua classe

Vedi anche se puoi definire un'interfaccia che copre le funzionalità di Trigger e Operation. Se non riesci a farlo, ciò indica che la tua classe sta diventando troppo grande. Inoltre interromperà l'accoppiamento tra voi classi.


1
In tutta onestà, non sono sicuro di poter rompere ulteriormente il mio codice. Ho aggiornato la mia domanda con le firme di classe in modo che tu possa vedere, ma fondamentalmente sono oggetti dati piuttosto leggeri che memorizzano alcune proprietà ciascuno. In termini di accoppiamento, sì, ciò è leggermente problematico, poiché efficacemente a Triggersarebbe accoppiato a a Operation. Ma è così che sembrano i dati del mondo reale. Sono accoppiati, perché esiste una mappatura, ad esempio devono conoscersi per avere un significato.
James Wood,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.