При проектуванні класів, призначених для успадкування (наприклад, абстрактних класів) вважається хорошим тоном не реалізовувати інтерфейс
Такий клас часто обов'язково повинен приймати як параметр якийсь об'єкт, без якого він не може нормально функціонувати, і надання конструктора за умовчанням порушить цілісність класу. У такій ситуації можна надати конструктор, але заборонити роботу з ним до його повноцінної ініціалізації. Для цього можна ввести в клас стан, і дозволити викликати його методи лише у випадку, якщо стан цього класу «ініціалізований». Приклад з книги "Effective java" :
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
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ