Sto lavorando su una classe che rappresenta un oggetto con rappresentazioni multiple: una è una rappresentazione di tipo XML utilizzata da un sistema di ordinamento automatico, l'altra è una rappresentazione basata su POJO utilizzata da uno strumento di monitoraggio.
Il problema che sto incontrando è che mi sembra di dover fare un compromesso tra l'incapsulamento dei dati interni dell'oggetto e la progettazione della mia applicazione secondo il principio della "separazione delle preoccupazioni" o "singola responsabilità per classe".
Diamo un'occhiata alla classe in modo più dettagliato:
public class MyObject {
private Object field1;
private Object field2;
private Object field3;
...
private Object field100;
}
(Sì, è piuttosto un brutto mostro brutto, qualcosa su cui non ho alcun controllo)
Se seguo il principio della separazione delle preoccupazioni (nel modo in cui lo capisco comunque), dovrò aggiungere i getter per ogni campo in questa classe e avere una classe XMLBuilder separata per la rappresentazione XML e un PojoBuilder per il monitoraggio rappresentazione dello strumento:
public class XMLBuilder {
public XML asXml(MyObject obj) {
return "<tag1>" + object.getField1() + "</tag1>"
"<tag2>" + object.getField2() + "</tag2>"
...
;
}
}
Questo mi sembra di infrangere il principio dell'incapsulamento: devo esporre molti dati interni sulla mia classe solo per fornire una rappresentazione per questo. Se passo il mio oggetto ad altri sistemi, non ho alcun controllo sul fatto che questi sottosistemi possano diventare dipendenti da campi arbitrari (es. Field45), il che significa che le future modifiche alla struttura di questo oggetto potrebbero diventare difficili dato che ora ci sono altre possibili dipendenze su di esso.
Un approccio alternativo, sostenuto da Allen Holub ( link ) per esempio, è quello di fare la rappresentazione all'interno della classe:
public class MyObject {
...
public XML asXml() {
return "<tag1>" + field1 + "</tag1>"
"<tag2>" + field2 + "</tag2>"
...
;
}
public Object asMonitor() {
...
}
}
Per me questa soluzione sembra ottima, poiché la classe non espone mai campi privati. I generatori di rappresentazione hanno accesso a tutte le informazioni di cui ha bisogno e l'oggetto stesso può essere tranquillamente passato ad altri sottosistemi senza la preoccupazione che un altro modulo dipenda da internals.
Ora, quando lo implemento, tutti i miei colleghi sollevano la questione della "Separazione delle preoccupazioni". Il problema, dicono, è che la classe MyObject ora ha conoscenza di cose come rappresentazioni XML e rappresentazioni POJO, il che significa che se la rappresentazione XML cambia, ora devi apportare modifiche all'interno della classe stessa stessa , invece di aggiornare semplicemente un "set di regole XML" o qualche altra configurazione esterna.
La soluzione di Holub consiste nell'utilizzare un modello di Builder:
public class MyObject {
...
public void buildContent(MyObjectBuilder builder) {
builder.setField1(field1);
builder.setField2(field2);
}
}
public class XMLBuilder implements MyObjectBuilder {
...
public void setField1(Object field1) {
content += "<tag1>" + field1 + "</tag1>";
}
public XML asXML() {
return content;
}
...
}
ma questo sembra difficilmente migliore del primo approccio - invece di esporre i dati come getter, ora è implicitamente esposto attraverso un costruttore. OK, capisco che con il builder potrei avere un controllo aggiuntivo su come il mio oggetto si rappresenta, ma è quel limite di controllo che vale la maggiore complessità nella base di codice? Le modifiche alla struttura di MyObject porteranno comunque probabilmente a dipendenze downstream che richiedono aggiornamenti, quindi non sono del tutto sicuro se molto è stato ottenuto qui (eccetto che ci sono tecnicamente nessun getters).
È un caso in cui devi semplicemente scegliere il tuo veleno? O c'è una via di mezzo magica che riduce tutti questi problemi? Quali sono le strategie comuni per affrontare questo?