Legge di Demetra che causa indecisione sottoclasse e conflitto con la singola responsabilità

4

Questa è la mia situazione:

Ho una classe chiamata CueList, che è fondamentalmente un wrapper attorno ad ArrayList. Ho un'altra classe chiamata TimeTicker che allerta tutti i Tickable (interfaccia) nella sua lista che è passato un certo periodo di tempo. Poiché ho bisogno di spuntare tutti gli elementi in CueList , ma non voglio violare DRY mantenendo una copia di tutti gli elementi di CueList nella classe TimeTickable (il che farebbe un incubo quando voglio per eliminare una Cue), il mio istinto immediato era di rendere CueList a Tickable e farlo passare il messaggio "tick" a tutti i suoi elementi.

Questo sembra violare il principio di Responsabilità Unica, che afferma che CueList non dovrebbe preoccuparsi di tenere traccia di tutti i segnali E di ticchettarli.

Quindi quello che ho fatto è stato creare una classe CueManager che è essa stessa Tickable e collega tutto (e spunta tutti gli elementi di CueList).

Ma ora, a causa della legge di demeter, ho un sacco di metodi duplicati in CueManager che rispecchiano solo la TimeTicker e la CueList class.

Questo non significa che la classe CueManager abbia più motivi per cambiare? Ciò non significa che viola il principio di responsabilità unica.

Inoltre, poiché la maggior parte dei metodi di CueManager mirror TimeTicker e CueList, non significa in realtà che sia un TimeTicker e CueList. Quindi non dovrebbe esserlo INHERIT da CueList e TimeTicker! (Ovviamente non puoi fare ereditarietà multiple in Java, ma ho l'impressione che abbia senso avere Eredita da CueList, ma che poi violerebbe la Single Responsibility)

Quindi in sintesi:

La legge di Demeter mi fa fare un mucchio di metodi che alterano altre due classi, ma questo mi fa pensare che dovrebbe davvero ereditare da entrambe le classi, ma ciò significherebbe che una classe gestisce più responsabilità ( anche se è attraverso la sua superclasse).

    
posta sinθ 23.07.2013 - 01:36
fonte

4 risposte

6

CueList è un ArrayList (o per lo meno può esporre un'interfaccia simile come Raccolta, Elenco o Iterable). Tutti gli elementi di quella lista array sono, apparentemente, tickable. TimeTicker non deve, e non dovrebbe, preoccuparsi che i suoi elementi siano in una CueList in particolare, né dovrebbe preoccuparsi che gli elementi nella lista su cui agisce siano tutt'altro che Tickable. Allo stesso modo, CueList non dovrebbe avere alcuna conoscenza di TimeTicker; non ha alcun effetto sulla funzionalità di base di CueList AFAICT. Questa è l'essenza del Least Knowledge Principle.

Quindi, fai in modo che TimeTicker agisca su un% co_de iniettato (o un ArrayList<Tickable> o un Collection<Tickable> o un List<Tickable> , qualunque interfaccia esponga i metodi che usi per scorrere attraverso questo elenco) e passi in CueList come questo dipendenza, tramite alcune classi che devono già conoscere sia la lista che il ticker.

    
risposta data 23.07.2013 - 01:53
fonte
5

Sembra il pattern Observer dove è normale che l'oggetto (TimeTicker) mantenga una lista dei suoi osservatori (Tickable ) in modo che possa aggiornarli su un evento. L'interfaccia Tickable può definire un metodo UnRegister() che puoi chiamare quando viene rimosso da qualsiasi elenco.

class TickableItem
{
    TimeTicker Subject;

    void UnRegister()
    {
        this.Subject.UnRegister(this);
    }

    void Register(TimeTicker subject) { ... }

    void OnTick() { ... }
}

Il vantaggio di questo approccio è che CueList non ha bisogno di sapere chi è il TimeTicker. Gli elementi leggibili sanno chi sono i TimeTicker (possono essere registrati con altri).

    
risposta data 23.07.2013 - 06:51
fonte
2

Quello che stai descrivendo è il pattern Observer e Java ha già due cose belle per questo in serbo. C'è l'osservatore dell'interfaccia e la classe astratta osservabile. Se si utilizzano questi due, TimeTicker non gestisce l'osservatore. TimeTicker si estende da Observable e fa solo le cose che deve fare. Trascorsa una certa quantità di tempo, chiama il metodo setChanged e notifyObservers .

Il tuo TimeTicker conosce 0 Tickables ( Observer ). La classe astratta Observable li conosce solo tramite l'interfaccia Observer . Ogni Tickable ora può registrarsi come osservatore sul TimeTicker senza problemi.

Detto questo non hai nemmeno bisogno di CueList più come la lista degli osservatori è gestita dalla classe astratta Observable .

    
risposta data 30.07.2013 - 09:15
fonte
1

Vorrei utilizzare il pattern Domain Events (google it) per permettere a TimeTicker e CueList di collaborare.

Quando è il momento giusto, TimeTicker potrebbe 'aumentare' ad un registro di handler un evento chiamato Tick. Il registro dei gestori passa quindi l'evento Tick a tutte le implementazioni registrate di

Handle<Tick>  { void Handle(Tick t); }

Ora hai le opzioni:

  • CueList potrebbe implementare Handle e spuntare i suoi membri.

  • ogni Cue potrebbe implementare Handle per sé stessa

  • o una classe generale TickHandler può ottenere CueList e aggiornare i cue

risposta data 23.07.2013 - 03:06
fonte

Leggi altre domande sui tag