У меня есть следующий класс
public class Num implements Serializable, Observable {
private int num; // number which should be serialized
// listeners who are watching for changes in this Num
// No need to serialize these -- pointless to do so.
private transient Set<Observer> listeners = new HashSet<>();
@Override public void addListener(Observer o) { listeners.add(o); }
@Override public void removeListener(Observer o) { listeners.remove(o); }
public void set(int newVal) {
if (num != newVal) {
num = newVal; // set the value.
for (Observer o : listeners)
o.notify(); // Notify listeners that the value changed.
}
}
}
Когда я сериализую этот класс, он работает хорошо и num
сохраняется. При десериализации класса num
загружается, а listeners
- нет и устанавливается на null
. Затем моя программа падает на линии for (Observer o : listeners)
.
Я нашел несколько решений, но все они ужасные решения.
1) Есть метод настройки, который 'реконструирует 'transient
поля.
public void setup() {
if (listeners != null) throw new Exception("Already setup!");
listeners = new HashSet<>();
}
Этот способ раздражает, потому что метод десериализации должен помнить, чтобы установить объект. Это очень не интуитивно понятно для других людей, работающих над проектом.
2) Имейте метод set
, чтобы автоматически проверять и восстанавливать себя
public void set(int newVal) {
if (num != newVal) {
if (listeners == null) listeners = new HashSet<>();
...
}
}
Этот способ также плохпотому что проверка будет повторяться снова и снова, даже если ее нужно было сделать только один раз.
3) Удалить Observable
из class Num
, избавиться от listeners
,и т. д. Затем создайте несериализуемый класс, содержащий экземпляр Num
.
public class Num implements Serializable {
public int num;
}
public class ObservableNum impements Observable {
private Num n;
public ObservableNum() { n = new Num(); } // constructor
private ObservableNum(Num n) { this.n = n; } // constructor
...
public static ObservableNum loadNum(...) {
ObjectInputStream ois = ...;
return new ObservableNum((Num) ois.readObject());
}
}
Но этот способ также кажется излишне сложным. Конечно, должно быть лучшее решение? Как правильно использовать переходный процесс?