Вопрос по constructor, private-members, java – Java устанавливает приватные поля внутри конструкторов

7

Обычная практика проектирования - сделать переменные экземпляра частными и иметь общедоступные методы получения и установки для доступа к ним. Но много раз я видел в Интернете примеры кода, в которых есть конструкторы, которые присваивают значения непосредственно закрытой переменной экземпляра, а не используют сеттеры внутри конструкторов. Я что-то пропустил?

public class Person{
    private String name;

    public Person(String name){
        //is this right, seems like the whole encapsulation purpose is defeated
        this.name = name;

        //shouldn't this be used
        setName(name);
    }

    public String getName(){
        return this.name;
    }

    public void setName(String name){
        this.name = name;
    }
}
В дополнениеthis ключевое слово не требуется для получателя; Это'используется только когдаs двусмысленность (то есть, если есть другая переменная с именем "название" в том же объеме) ataulm
Я считаю, что цель сделать переменные частными - изолировать их от прямого манипулированияДругой классы. PM 77-1

Ваш Ответ

10   ответов
6

Вы ничего не упускаете. То, что вы делаете, полностью зависит от вашей ситуации. Однако учтите это:

Очень часто проверка параметров выполняется в установщике. Например, пустьскажем, у меня есть класс с полем, которое может содержать значение от 0 до 10 ("броски» не требуется для типа исключения ниже, но я включил его для ясности):

public class Example {
    private int value; 
    public Example () {
    }
    public final int getValue () {
        return value;
    } 
    public final void setValue (int value) throws IllegalArgumentException { 
        if (value < 0 || value > 10)
            throw new IllegalArgumentException("Value is out of range.");
    }
}

Здесь setValue () проверяетзначение' чтобы убедиться, что он придерживается правил. У нас есть инвариант, который утверждаетПример не будет существовать со значением вне диапазона ", Теперь давайтескажем, мы хотим создать конструктор, который принимает значение. Вы можете сделать это:

public class Example {
    ...
    public Example (int value) {
        this.value = value;
    }
    ...
}

Как видите, есть проблема. Оператор new Example (11) будет успешным, и теперь существует Example, который нарушает наши правила. Однако, если мы используем сеттер в конструкторе, мы можем также легко добавить валидацию всех параметров в конструктор:

public class Example {
    ...
    public Example (int value) throws IllegalArgumentException {
        setValue(value); // throws if out of range
    }
    ...
}

Таким образом, есть много преимуществ для этого.

Теперь все еще есть случаи, когда вы можете назначить значения напрямую. Для одного, может быть, вы неу него нет доступных сеттеров (хотя я бы сказал, что создание приватных сеттеров или приватных сеттеров по-прежнему желательно по причинам, указанным выше, для поддержки отражения / bean-компонента, если это необходимо, и для простоты проверки в более сложном коде).

Другая причина может заключаться в том, что, возможно, у вас есть конструктор, который каким-то образом заранее знает, что допустимые значения будут назначены, и поэтому не 'не требует проверки и может назначать переменные напрямую. Это обычно не является веской причиной, чтобы пропустить использование сеттеров.

Тем не менее, в целом, этоКак правило, хорошая идея использовать сеттеры везде, где это возможно, обычно приводит к более чистому и ясному коду, который легче поддерживать по мере увеличения сложности.

Большинство примеров, которые вы видите, когда люди устанавливают переменные, являются просто людьми "ленивый» - что вполне приемлемо, если ситуация этого требует (возможно, вывы пишете программу быстрого тестирования или приложение и ненапример, я не хочу реализовывать несколько сеттеров). Там'В этом нет ничего плохого, если вы помните общую картину и будете тольколенивый» когда это'уместно.

Что-то яЯ хотел бы добавить, основываясь на некоторых других ответах здесь: Если вы переопределяете установщик в подклассе, и данные, которые вы устанавливаете, нарушают инварианты, которые предполагает базовый класс, то либо соответствующие сеттеры должны быть сделаны окончательными, либо базовый класс должен не делать эти предположения.Если переопределение сеттеров нарушает инварианты базового класса, тогда возникает более серьезная проблема.

Вы'Вы заметите, что получатель / установщик является окончательным в приведенном выше примере. Это потому, что наше правило таковолюбой пример должен иметь значение от 0 до 10 ", Следовательно, это правило распространяется на подклассы. Если бы у нас не было этого правила, и если бы Пример мог принимать какое-либо значение, нам не понадобился бы окончательный установщик и мы могли бы переопределить подклассы.

Надеюсь, это поможет.

0

Это не отменяет инкапсуляцию, так как закрытый член все еще скрыт от других классов.

Если метод модификатора не содержит никакой логики и просто устанавливает член, то нет никакой разницы между прямой установкой члена вызова его метода установщика, хотя для лучшей практики следует вызывать установщик.

Сеттер указывает, что этот человекИмя s может измениться в будущем и позволяет легко, без повторного создания объекта person.

0

Установка переменных в private означает поощрение инкапсуляции из других классов.

Если неsetName(String) должен был сделать что-то лишнее (что имя метода не делаетэто)Нет необходимости использовать сеттер, пока вынаходится в классе, где частная переменная.

Это неполностью истина, поскольку вы можете инкапсулировать всю свою логику проверки в установщике и, таким образом, иметь службы проверки из других мест вашего класса. Jason C
+1 уверен, согласен. ataulm
2

В зависимости от контекста использование методов получения и установки фактически является более серьезным нарушением инкапсуляции, чем использование переменных-членов в конструкторах. Если вы хотите установить переменную-член 'название' этого класса, любой из этих подходов будет работать, так как конструкция скрыта от вызывающей стороны и, следовательно, не нарушает инкапсуляцию. Одним из предупреждений является то, что использование setName в конструкторе может вызвать переопределенный метод в подклассе, который может быть не тем, что вы хотите (так как это может оставить имя неопределенным в суперклассе).

Вот's похож на ваш вопрос, который может дать дополнительную информацию:

вызов сеттера из конструктора

0

Это совершенно нормально. Некоторые переменные, возможно, потребуется инициализировать, как только объект будет создан, поэтому имеет смысл передать их в конструктор, и во многих случаях мы можем не захотеть предоставлять установщики для этих переменных, чтобы избежать изменения значений после создания объекта.

Существует аргумент, в основном касающийся валидации (особенно для переменных, которые могут быть установлены в нескольких местах), для того, чтобы вместо этого иметь частные установщики. Но это очень верно, иногда вы просто хотите быстро собрать простой код, и создавать частные сеттеры с минимальными преимуществами неудобно. Jason C
0

Инициализация переменных внутри конструктора - очень распространенная практика. Его можно использовать для присвоения значений переменным в зависимости от того, какой конструктор вызвал пользователь. Вы не можете писать код, основываясь на предположении, что клиентский код вызовет метод установки для присвоения значения переменным экземпляра. Всегда безопасно присваивать значение по умолчанию переменной при создании ее объекта (т.е. внутри конструктора).

Существует различие между инициализацией переменных в конструкторе и установкой его в другое значение в соответствии с требованием вызывающего кода (с использованием метода setter). Оба имеют разные цели и разные цели.

Я нене думаю, что это отвечает на вопрос (или, может быть, я неправильно понял). ОП нетне спрашиваю ли этоправильно инициализировать переменные в конструкторе, когда вы уже предоставили установщики; скорее, ОП спрашивает оиспользование указанных сеттеров из конструктора. ataulm
2

Иногда, когда вы хотите сделать класс неизменным, это всего лишь одна из вещей, которые вам нужно сделать. И не надов этом случае вообще нет методов установки.

Существует аргумент, в основном касающийся проверки, для того, чтобы вместо этого иметь частные сеттеры. Но это очень верно, иногда вы просто хотите быстро собрать простой код, и создавать частные сеттеры с минимальными преимуществами неудобно. Jason C
0

Это нормально, чтобы напрямую присваивать значения в классе при условии setn 'не делаю никакой другой обработки.

В основном сеттеры / геттеры используются для предоставления ограниченного доступа к частным данным, таким как возврат копии данных вместо ссылки на частный объект, проверка данных в геттере и т. Д.

Поскольку конструктор является частью самого объекта, и мы уверены, что то, что мы делаем, правильно, то все в порядке.

Это'Стоит отметить, что ключевое утверждение здесь "и мы уверены, что мы делаем правильно, Если вы когда-либо налагаете правила на значения ваших полей, нене забудьте позаботиться о том, чтобы конструктор ненарушать эти правила. Jason C
0

Мой предпочтительный подход (как описано Джошуа Блохом вЭффективная Java "), чтобы сделать конструктор частным, сделать поля окончательными (то есть полностью исключить установщики) и требовать, чтобы клиенты получали экземпляры, либо используяОбразец Строителя или жеШаблон фабричного метода, который позаботится о любой необходимой проверке для защиты инвариантов. Тогда (приватный) конструктор просто напрямую назначит заданные параметры (которые уже были проверены с помощью Builder или Factory Method) соответствующим полям, которыеprivate а также .final

0

закрытые переменные доступны прямо в любом месте класса

урегулирование частных переменных заключается в инкапсуляции их из других классов

Похожие вопросы