Как сделать класс java неизменным, если в нем есть переменная-член другого пользовательского класса?
Недавно в интервью для роли Java Developer меня спросили, как сделать Class A неизменным, если у него есть переменная-член, которая является объектом Class B, и в ситуации, когда Class B является внешним по отношению к проекту и не может быть отредактирован кроме того, у программиста класса B может быть даже собственная переменная-член, которая является объектом другого определенного пользователем класса. Я много думал об этом и сказал интервьюеру, что нет никакого способа, если класс В не внедрил метод и не подверг его глубокому клонированию.
Интервьюер, хотя и не был убежден. Есть ли способ сделать такой класс неизменным?
Если я правильно помню, это была ситуация, которую он объяснил. Он хотел, чтобы я сделал класс А неизменным, что было бы лучшим ответом?
final public class A {
final private B b;
A(B b) {
this.b = b; // Class b might/might not be cloneable
// this.b = (B)b.clone();
}
public B getB() {
return b;
// return (B)b.clone();
}
}
class B // external cannot edit
{
C c;
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
class C // external cannot edit
{
int i;
String j;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public String getJ() {
return j;
}
public void setJ(String j) {
this.j = j;
}
}
2 ответа
Не выставляй Б миру. Так что нет метода, который возвращает B.
Вместо этого определите методы в B, которые не видоизменяют B и позволяют A реализовать эти методы, вызывая тот же метод в b.
Поэтому, если у B есть метод calcSomething(), a должен иметь метод calcSomething(), который просто возвращает b.calcSomething().
Вы можете использовать что-то вроде этого:
final public class A {
final private B b;
A(B b) {
this.b = cloneB(b);
}
public B getB() {
return cloneB(b);
}
private static B cloneB(b){
B newB = new B();
C c = new C();
c.setI(b.getC().getI());
c.setJ(b.getC().getJ());
newB.setC(c);
return newB;
}
}
В этом случае класс A является на 100% неизменным.
Обновление: Также вы можете использовать отражение или разделение, чтобы получить глубокую копию класса (если класс имеет глубокую иерархию), например, используя GSON для выделения:
private static B cloneB(b){
String tmp = new GSON().toJson(b);
return new GSON().fromJson(tmp, B.class);
}
или так далее