Изучите следующий код:
public class ClassA {
private boolean ClassAattr = false;
public ClassA() {
ClassAHandler handler = new ClassAHandler(this);
}
}
public class ClassAHandler extends GeneralHandler {
ClassA ca = null;
public ClassAHandler(ClassA classa) {
this.ca = classa;
}
}
Я должен получить доступ ClassAattr
на некоторых ClassAHandler
методы, среди других атрибутов. Есть ли способ сделать так, не передавая класс источника в конструкторе обработчика. Мне действительно не нравится, как это решение "смотрит".
На этой странице есть очень хорошее объяснение того, почему пропускать ссылку «this» - плохая идея:
http://www.ibm.com/developerworks/java/library/j-jtp0618 .html # 2
Отметьте раздел "Не публиковать" эту "ссылку во время создания"
Вы можете использовать внутренние классы, тогда между двумя экземплярами существует неявная родительско-дочерняя связь. (Но я не знаю, действительно ли это лучше).
public class ClassA {
private boolean ClassAattr = false;
public class ClassAHandler extends GeneralHandler {
public ClassAHandler() {
// can access ClassAattr
}
}
public ClassA() {
ClassAHandler handler = new ClassAHandler();
}
}
Если вы передадите this
, подклассу потребуется доступ к родительскому значению с помощью parent.classAattr
. Мы можем задаться вопросом, правильно ли это согласно закону Деметры .
Другой вариант заключается в том, что ClassA
передает всю информацию, которая требуется ClassAHandler
в конструктор. Если обработчику требуется значение ClassAttr
, передайте его в конструктор.
public ClassA() {
ClassAHandler handler = new ClassAHandler( classAattr );
}
Но параметр передается по значению, поэтому я не знаю, работает ли он для вас.
Третий вариант - немного изменить схему и сохранить в обработчике логическое значение
. Затем ClassA
обращается к значению дочернего элемента с помощью handler.handlerAttr
. Дочерний ребенок ничего не знает о родителе, но родитель может получить доступ к такой информации в ребенке, какой пожелает. Это лучше относительно закона Деметра .
public class ClassAHandler extends GeneralHandler {
boolean handlerAttr;
public ClassAHandler() {
}
}
Напишите метод получения для ClassAattr как
public boolean isClassAattr(){
return this.ClassAattr;
}
, чтобы вы могли получить к нему доступ как ca.isClassAattr ();
Вы можете сделать ClassAHandler внутренний класс ClassA. У него будет доступ к членам ClassA.
В коде, который вы вставили, нет ничего плохого, однако вы можете использовать не статический внутренний класс, чтобы сделать вещи (возможно) чище:
public class ClassA {
private boolean ClassAattr = false;
public ClassA() {
ClassAHandler handler = new ClassAHandler();
}
class ClassAHandler extends GeneralHandler {
// magically sees the instantiating ClassA members and methods
}
}
Передача this
другому методу/объекту изнутри конструктора может быть довольно опасной. Многие гарантии, которые обычно выполняют объекты, не обязательно верны, если смотреть на них изнутри конструктора.
Например, если в вашем классе есть поле final
(не static
), то обычно вы можете рассчитывать на то, что оно будет установлено в значение и никогда не изменится.
Если объект, на который вы смотрите, в данный момент выполняет свой конструктор, то эта гарантия больше не действует.
В качестве альтернативы вы можете отложить создание объекта ClassAHandler
до тех пор, пока он впервые не понадобится (например, выполнив ленивую инициализацию в геттере этого свойства).
Создайте метод registerHandler(ClassA handler).
Невозможно создать обработчик для чего-то, о чем обработчик не знает.
Если я правильно понимаю, вам нужно, чтобы обработчик имел ссылку на ClassA
, но вы не хотите настраивать это из конструктора ClassA
?
Если это так, то вы можете отделить построение от "подключения" с помощью фабричного шаблона, что предотвратит потребность вашего ClassA
в информации о ClassAHandler
класс. Примерно так:
public class ClassA {
private boolean ClassAattr = false;
public ClassA() {
}
}
public class ClassAHandler {
private ClassA ca = null;
public ClassAHandler(ClassA classa) {
this.ca = classa;
}
}
public HandlerFactory {
public ClassAHandler createClassAHandler(ClassA classa) {
ClassAHandler handler = new ClassAHandler(classa);
return handler;
}
}