#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, намного проще отслеживать, где осуществляется доступ к каждому полю.