При проектуванні класів, призначених для успадкування (наприклад, абстрактних класів) вважається хорошим тоном не реалізовувати інтерфейс
Serializable
і індивідуально в кожному класі-спадкоємці вирішувати, чи потрібна його серіалізація чи ні. Однак у такому класі обов'язково має бути конструктор за умовчанням, щоб механізми серіалізації правильно створабо об'єкт. І іноді немає можливості надати конструктор за умовчанням, не порушивши цілісність класу. Такий клас часто обов'язково повинен приймати як параметр якийсь об'єкт, без якого він не може нормально функціонувати, і надання конструктора за умовчанням порушить цілісність класу. У такій ситуації можна надати конструктор, але заборонити роботу з ним до його повноцінної ініціалізації. Для цього можна ввести в клас стан, і дозволити викликати його методи лише у випадку, якщо стан цього класу «ініціалізований». Приклад з книги "Effective java" :
public abstract class AbstractFoo {
private int x, y;
private enum State {
NEW, INITIALIZING, INITIALIZED
};
private final AtomicReference<State> init = new AtomicReference<State>(State.NEW);
protected AbstractFoo() {}
public AbstractFoo(int x, int y) {
initialize(x, y);
}
protected final void initialize(int x, int y) {
if (!init.compareAndSet(State.NEW, State.INITIALIZING)) {
throw new IllegalStateException("Already initialized");
}
this.x = x;
this.y = y;
init.set(State.INITIALIZED);
}
protected final int getX() {
checkInit();
return x;
}
protected final int getY() {
checkInit();
return y;
}
private void checkInit() {
if (init.get() != State.INITIALIZED) {
throw new IllegalStateException("Uninitialized");
}
}
}
class Foo extends AbstractFoo implements Serializable {
private void readObject(ObjectInputStream s) throws IOException,
ClassNotFoundException {
s.defaultReadObject();
int x = s.readInt();
int y = s.readInt();
initialize(x, y);
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(getX());
s.writeInt(getY());
}
public Foo(int x, int y) {
super(x, y);
}
}
При цьому всі методи цього класу повинні перевіряти поточний стан класу та запобігати неправильному його використанню, а в класі-спадкоємці повинні визначатися методи readObject()
та writeObject()
. Посилання на першоджерело: http://0agr.ru
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ