Почему бы не использовать атрибут напрямую, но использовать метод getXXX()

#java #encapsulation

#java #инкапсуляция

Вопрос:

В некотором методе объекта домена они не использовали атрибут напрямую, а использовали метод get . Почему? Один из следующих примеров:

 private List<String> errorCodeList = new ArrayList<String>();  

/** 
 * Add all errors to the error list.
 */
public void addAllErrors(Collection<String> theErrorStrings) {
    if (errorCodeList == null) {
        errorCodeList = new ArrayList<String>();
    }

    for (String aString: theErrorStrings) {
        getErrorCodeList().add(aString);
    }
}


/**
 * @return the errorCodes
 */
public List<String> getErrorCodeList() {
    return errorCodeList;
}
/**
 * Set the error strings.
  */
public void setErrorCodeList(List<String> allErrors) {
    this.errorCodeList = allErrors;
}
 

Комментарии:

1. Одно из преимуществ, которое вы можете видеть из своего кода, заключается в том, что вы можете возвращать List<String> вместо ArrayList<String>

2. Это может быть просто результатом рефакторинга в Eclipse при введении getter и setter .

Ответ №1:

Это вопрос инкапсуляции. Предоставляя доступ к переменным экземпляра только через геттеры и сеттеры, вы скрываете внутреннее представление. Таким образом, вы можете впоследствии изменить реализацию, не изменяя интерфейс. Вы можете решить, что было бы удобнее использовать HashMap для хранения кодов ошибок (по любой причине), и как только вы это измените, весь код, обращающийся к полю, сломается. Однако, если вы предоставили getter и setter, вы можете сохранить их такими, какие они есть, несмотря на ваше измененное внутреннее представление.

В дополнение к этому проще обеспечить сохранение инвариантов на месте, чего вы не смогли бы сделать, если бы все могли получить доступ к полям.

Комментарии:

1. поддержано. пока вы выполняете интерфейс (даже внутри класса), внутреннее представление не меняется, и вы поддерживаете хорошую практику кодирования (от того, кто читает код)

2. Вопрос касался использования поля в том же классе, в котором определены оно и средство получения.

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

Ответ №2:

Лично я не сторонник доступа к полям в одном классе с помощью их методов получения: инкапсуляция не нарушается, если избегать вызова getter, потому что вы пишете код в том же определении класса. Кроме того, использование геттеров делает код более загроможденным и не обеспечивает эффективную подсветку синтаксиса.

Очевидно, что существуют исключения, когда вам приходится обращаться к полю через средство получения:

  • Когда он создается лениво.
  • Когда средство получения вычисляет значение на лету.

Комментарии:

1. еще одна причина, несмотря на сомнительность: если геттер должен быть переопределен в подклассе

Ответ №3:

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

 public void addAllErrors(Collection<String> theErrorStrings) {
    for (String aString: theErrorStrings) {
        getErrorCodeList().add(aString);
    }
}

public List<String> getErrorCodeList() {
    // TODO synchronization?
    if (errorCodeList == null) {
        errorCodeList = new ArrayList<String>();
    }

    return errorCodeList;
}
 

Ответ №4:

Это инкапсуляция:

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

Более подробная информация доступна здесь .

Комментарии:

1. Вопрос касался доступа изнутри класса, в котором определено поле / средство получения.

Ответ №5:

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

Это также может облегчить статический анализ кода, поскольку весь доступ к полю (либо из класса, либо без него) осуществляется с помощью одного метода.

Конечно, есть компромисс с дополнительным вызовом метода (если только компилятор не достаточно умен, чтобы выполнить преобразование).

Тем не менее, я согласен с Адамски, я тоже не фанат этого.

Ответ №6:

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