Migliorare la coesione e l'accoppiamento delle classi
-
28-10-2019 - |
Domanda
Mi viene dato questo set di codice e devo suggerire modi per migliorare la coesione e l'accoppiamento del codice delle classi. Ma ho pensato che queste classi fossero abbastanza ben accoppiate dal momento che sembra che stiano facendo uso di eventi. E in termini di coesione, tutte le chiamate init () sono messe insieme, tutto mi sembra abbastanza bene.
public class A
{
private C t;
private B g;
public static void main(String args[]) {
// Creates t and g.
t = new C();
t.init();
g = new B();
g.init();
g.start(this);
}
pubic void update (Event e)
{
// Performs updating of t based on event
}
}
public class C
{
public C() { ... }
public void init() { ... }
}
public class B
{
public B() { ... }
public void init() { ... }
public void start(A s) {
e = getNextEvent();
while (e. type != Quit)
if (e.type == updateB)
update(e) ;
else
s.update(e) ;
e = getNextEvent();
}
public void update(Event e) { ... }
}
}
Esistono ancora modi per migliorare la coesione e l'accoppiamento delle classi? Mi sembra a posto ma penso che mi manchi qualcosa.
Grazie per eventuali suggerimenti su questo.
Soluzione
Un suggerimento sarebbe quello di disaccoppiarsi la logica di gestione degli eventi dalla logica del controller (Classe A).
Quindi avresti 4 tipi di classi:
- La classe principale utilizzata per l'esecuzione del "server" (a)
- il thread che ascolta gli eventi (B)
- il livello modello che verrà aggiornato (C)
- Una classe di gestori di eventi che supporterà alcune operazioni su un evento (D)
Potrebbe assomigliare a questo:
public class Main {
private Model m;
private EventListener listener;
... main() {
m = new Model();
listener = new EventListener();
EventHandler eventHandler = new MyEventHandler();
// set the event handler
listener.setEventHandler(eventHandler);
listener.start(m);
}
public class Model {
// nothing to see here
}
public class EventListener() {
private EventHandler handler = new DefaultEventHandler();
public void start(final Model m) {
// startup
while (event.type != Event.Quit) {
// get event
handler.handleEvent(event, m);
}
// shutdown
}
public void setEventHandler(EventHandler eh) { this.handler = eh }
}
public class MyEventHandler implements EventHandler {
public void handleEvent(Event e, Model m) {
// update the model
}
}
Si noti che in questo nuovo design la logica aziendale dell'aggiornamento del modello (C nel tuo esempio) è passata a una classe esterna rispetto alla classe "Runner". Questo è un po 'più pulito in quanto la classe principale non ha bisogno di conoscere quali eventi sono e come gestirli.
Un altro vantaggio è che l'utilizzo di questo puoi facilmente codificare la gestione degli eventi complessi utilizzando gestori di eventi incatenati o più gestori di eventi seriali. È anche abbastanza semplice implementare la gestione degli eventi asincrona poiché B è responsabile solo di chiamare i gestori e non è necessario comprendere i tipi di eventi. Questo a volte viene definito come Pubblica/iscriviti e mantiene l'ascoltatore (b) e il gestore (il tuo metodo di aggiornamento (e)) accoppiato vagamente
Altri suggerimenti
Inizia a scrivere test unitari (meglio ancora, fai TDD). L'accoppiamento (e, in misura minore, la coesione o la sua mancanza) diventerà immediatamente evidente.
Ad esempio, il metodo di avvio della Classe B ha un parametro di tipo A. Nel tuo esempio potresti semplicemente istanziare A, ma cosa succede se A avesse altre dipendenze? Forse tutte le esigenze di avvio sono un'interfaccia che un implementa (con un metodo di aggiornamento).
E cosa fa getNextevent? Se utilizza altre dipendenze, ottenere B in un imbracatura di prova può rivelarsi difficile.
I test possono aiutare a convalidare il tuo design.
Senza vedere più del tuo codice è difficile dire quanto sia disaccoppiato il tuo codice. Gli eventi sono un modo per disaccoppiarsi, ma possono anche rendere il codice più difficile da capire e eseguire il debug.
Durante la progettazione di lezioni, ad alta collaborazione significa che molti dei metodi si riutilizzano a vicenda e il basso accoppiamento significa che devi solo esporre alcuni metodi pubblici.
Durante la progettazione di pacchetti, ad alta coezione significa che molte delle classi in un pacchetto dipendono l'una dall'altra e il basso accoppiamento significa che solo pochi sono ambito pubblico o un messaggio con altre classi attraverso interfacce.
I benefici dell'alta coezione, a basso contenuto di acquisizione dovrebbero essere meno dolore, specialmente quando si tratta di rispondere al cambiamento. Se non riduce il dolore, non passare molto tempo a ottimizzarlo. So che sembra che io stia lanciando banalità qui, ma dovresti tenere a mente la tua metrica quando misurano se ad alta collaborazione e bassa accoppiamento è "abbastanza buono" piuttosto che fare affidamento sulle opinioni delle persone che non comprendono necessariamente il Problema che stai cercando di risolvere.
Se il design originale è quello di incorporare un'altra funzionalità o classi in futuro, usando un gestore di eventi, come hai detto, è stato utilizzato, quindi concentrati sul modello di strategia sull'implementazione e sull'ottimizzazione su classi o interfacce.