Quindi, al momento hai:
public class ImportantInfo {
// constructor
public ImportantInfo() { ... }
// getter
public Data getData() { ... }
// dangerous setter
public void setData(Data d) { ... }
}
Gestione della mutevolezza
Per prima cosa, forse non vuoi includere un metodo set di default. Per un altro, probabilmente non vuoi un costruttore pubblico. Forse hai già una fabbrica, ma la tua fabbrica potrebbe restituire un'interfaccia immutabile (che non espone il metodo impostato). L'interfaccia seguente ha un metodo che restituisce l'implementazione mutabile, ma che richiede lavoro (quindi le persone non lo faranno per caso) e il nome del metodo fornisce un avvertimento:
public interface ImportantInfo {
public Data getData();
// ... expose any other safe methods here ...
public ImportantInfoImplementation getMutableImplementionButBeCareful();
}
Ora usa un costruttore privato per ImportantInfo e un metodo factory che restituisce l'interfaccia immutabile:
public class ImportantInfoImplementation {
// constructor is now private so people can't instantiate this
// willy-nilly.
private ImportantInfoImplementation() { ... }
// public factory method is now the way to get instances of this class
// and you only get the interface which doesn't expose the dangerous
// method.
public static ImportantInfo of() {
return new ImportantInfoImplementation();
}
// getter is mentioned in the interface
@Override
public Data getData() { ... }
// dangerous setter is hidden by the interface.
public void setData(Data d) { ... }
// returns the mutable implementing class.
@Override
public ImportantInfoImplementation getMutableImplementionButBeCareful() {
return this;
}
}
Ora per utilizzare il metodo pericoloso, i client devono chiamare:
ImportantInfo ii = ImportantInfoImplementation.of();
// Living free and easy with safe immutable version.
someUntrustedMethod(ii);
// probably not messed up yet!
ii.getData();
// OK, I want it badly enough...
ii.getMutableImplementionButBeCareful().setData(d);
Penso che @Izkata stia girando per qualcosa di simile a quanto sopra, ma non ne sono sicuro.
Sfruttando l'immutabilità
Non sono sicuro che il tuo metodo set esponga qualche pericolo sottostante, o se rende instabile l'istanza di questa classe. Se il primo, questo non ti aiuterà, ma se quest'ultimo, questo potrebbe risolvere il tuo problema: Rendi la tua classe immutabile:
public class ImportantInfo {
private static final Data data;
// constructor
public ImportantInfo(Data d) {
data = d;
}
// getter
public Data getData() { return d; }
// no-longer dangers setter returns a new ImportantInfo leaving
// the old one unchanged.
public ImportantInfo setData(Data d) {
return new ImportantInfo(d);
}
}
Ora se si chiama setData () il vecchio oggetto ImportantInfo è invariato e il codice client ottiene un nuovo oggetto ImportantInfo che riflette lo stato modificato. Ovviamente, anche il tuo oggetto Data deve essere immutabile perché funzioni correttamente. Se Data è o contiene una raccolta di qualche tipo, puoi trovare il mio suggerimenti per rendere le raccolte immutabili in Java per essere utili. Aggiornamento 2017-09-14: invece di quello che ho utilizzato Paguro per eliminare o gestire la maggior parte mutazione in Java.
Deprecation
Se nessuno di questi ti rende felice, potresti deprecare il metodo setData () in modo che le persone debbano sopprimere l'avviso per usarlo. Non mi piace abbastanza, ma potrebbe essere perché non prevedo il motivo per cui è male chiamare questo metodo.
// Be careful when setting data because
// 1. first reason
// 2. second complication
// 3. ...
@Deprecated
public void setData(Data d) { ... }
Conclusione
In ogni caso, mi piace l'idea di dare alle persone un facile accesso alla cosa sicura, ma fargli fare più lavoro per ottenere la cosa pericolosa. Ad ogni modo, per favore spiega esattamente cosa fare attenzione, e perché questo è un problema, in modo che le persone sappiano a cosa stanno entrando prima che lo usino.