Sto implementando un sistema di trigger. Ci sono oggetti che assumono il ruolo di osservatori (questo non è un modello strettamente osservatore perché gli osservatori sono interdipendenti, vedi la mia domanda qui ). Si registrano per essere attivati durante determinati eventi (essendo aggiunti all'elenco di quell'evento) e forniscono la funzionalità quando si verifica un evento del genere (implementando il metodo appropriato).
Ho la seguente interfaccia:
public interface Triggerable {
public boolean triggerOnEvent1();
public boolean triggerOnEvent2();
public boolean triggerOnEvent3();
// etc.
}
e liste "corrispondenti" raggruppate in questa classe:
public class TriggerManager {
static List<Triggerable> objectsToTriggerOnEvent1;
static List<Triggerable> objectsToTriggerOnEvent2;
static List<Triggerable> objectsToTriggerOnEvent3;
// etc.
// Getters for the lists: getObjectsToTriggerOnEventx()
}
Sto usando un modello di adattatore qui, che penso sia irrilevante per la domanda, ma rende il codice più facile da leggere:
public abstract class AbstractTrigger implements Triggerable {
@Override
public boolean triggerOnEvent1() { return false; }
@Override
public boolean triggerOnEvent2() { return false; }
@Override
public boolean triggerOnEvent3() { return false; }
// etc.
}
Questo è un esempio di "trigger":
public class TriggerExample extends AbstractTrigger {
public TriggerExample () {
// register to specific events
TriggerManager.getObjectsToTriggerOnEvent2().add(this);
TriggerManager.getObjectsToTriggerOnEvent6().add(this);
}
@Override
public boolean triggerOnEvent2() {
// do something
return true;
}
@Override
public boolean triggerOnEvent6() {
// do something else
return true;
}
}
Quando un evento accade da qualche parte, viene notificato a tutti gli "osservatori" registrati usando questa iterazione:
for (int i = 0; i < TriggerManager.getObjectsToTriggerOnEventx().size(); i++) { // x stands for any of the above numbers
Triggerable triggerable = TriggerManager.getObjectsToTriggerOnEventx().get(i);
if (triggerable.triggerOnEventx()) {
// do something
}
}
Le implementazioni di triggerOnEventx
variano notevolmente e loro stessi possono causare trigger con il costrutto di loop sopra.
Le mie preoccupazioni sono duplici:
- Ho bisogno di mantenere gli stessi dati due volte - per ogni metodo che aggiungo / rimuovi dall'interfaccia (e dall'adattatore), ho bisogno di aggiungere / rimuovere una lista. Riduce la manutenibilità.
- Devo stare attento a non utilizzare la combinazione sbagliata di un elenco e un metodo nell'iterazione - iterando su
listx
chiameremo sempremethodx
sul suo contenuto. Prone di bug.
Una cosa che ho pensato di fare è creare un Map<List, Method>
per risolvere il punto 2. Il fatto è che non risolve 1 e che usa il riflesso, che viene fornito con i suoi problemi (come ottenere il metodo da nome, che è anche soggetto a bug).
Posso modificare entrambi i tipi sopra e creare nuove cose, quindi la soluzione non deve essere limitata alla struttura sopra. Qual è un buon design che si adatta a questo?