Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Чем канонические геттеры и сеттеры лучше открытого поля?

#java #ооп


Не понимаю, в чем плюс использования канонических (только возвращающих и устанавливающих
занчение) геттеров и сеттеров перед открытым полем? Чем вот такой код:

private MyJDesktopPane desktop;

public MyJDesktopPane getDesktop() {
    return desktop;
}

public void setDesktop(MyJDesktopPane desktop) {
    this.desktop = desktop;
}


Лучше такого:

public MyJDesktopPane desktop;


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

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


Ответы

Ответ 1



Это "запас на будущее". Сейчас вам достаточно поля, так как у вас публичны и чтение, и запись, а никакой дополнительной логики нет. Теперь допустим, что вам понадобилась эта логика. Что вы будете делать? Вы скроете поле, напишете геттеры и сеттеры. И тут возникает проблема: надо переписать все доступы к полю во всех классах, работающих с вашим кодом; надо перекомпилировать весь код, который обращается к полю. Часто это может быть большой объём работы, и он может повлечь за собой тьму тьмущую неприятностей, особенно если одновременно поддерживается несколько версий приложения: привет конфликтам мержа кода и прочим радостям. Всё потому, что изменение поля на геттеры и сеттеры — это изменение, ломающее обратную совместимость, а добавление логики в геттер или сеттер — совершенно безболезненное изменение реализации. При хорошей архитектуре изменение реализации не должно влиять на внешний интерфейс и не должно ломать обратную совместимость. Поэтому предпочтение отдаётся геттерам и сеттерам даже тогда, когда реальной нужды в них нет. Лирическое отступление: в C# синтаксис доступа к публичным полям и к публичным свойствам (парам геттер+сеттер) идентичен. Однако даже в C# считается дурным тоном использование публичных полей. Во-первых, потому что ломается бинарная совместимость, несмотря на сохранение совместимости на уровне сорцов; во-вторых, потому что публичные поля могут быть переданы по ссылке (ref, out), что невозможно для свойств. Прочитал статью. Надо заметить, что рекомендация воздерживаться от геттеров и сеттеров в статье универсальна и оторвана от конкретных языков. Нельзя реализовать все рекомендации из статьи, если оставаться в рамках синтаксически аскетичного языка. Вы не можете воспользоваться синтаксическии сахаром в виде свойств, которые выразительнее, чем геттеры и сеттеры, если язык эти свойства не поддерживает. В этом случае придётся использовать геттеры и сеттеры, а не публичные поля, впрочем. Ну или переходите на C#. :)

Ответ 2



В вызваном из контекста примере ничем. Например разницы между class A { public int a; } и class A { private int a; public int getA() { return a; } public void setA(int a) { this.a = a; } } нет. Однако, в любой более менее адекватной ситуации лучше использовать getter'ы и setter'ы, причины могут быть следующие Поле нельзя вынести в интерфейс. Даже если сейчас у класса нет интерфейса, но его захочется добавить позже, гораздо проще будет переделать методы, чем жёсткую привязку к полю. Если будет требоваться добавить дополнительную логику при установке поля, то так же изменений будет требоваться минимум. Метод можно пометить как synchronized. Таким образом можно сделать вывод, что по большей части мы обеспечиваем расширяемость.

Ответ 3



Потому что один из принципов ООП это как раз инкапсуляция - скрытие внутренней логики класса. Если другие классы будут иметь прямой доступ к публичной переменной класса - тогда вообще возникает вопрос, почему этот класс ей "обладает", если реально - не обладает :) В общем логика программы будет страдать, опасность путаницы и одновременного доступа из разных методов и т.д.. Хочется публичных переменных, и методы только заполняющие поля - заводи структуру.

Ответ 4



Добавлю, что публичные поля имеют право на существование в некоторых случаях: Поля объявлены в непубличном классе. Тогда весь класс — это деталь реализации и с полями может быть проще и быстрее, чем с сеттерами. Поля объявлены final и содержат примитивное значение, либо ссылку на неизменяемый объект (например, String). Сеттера тогда, понятно, не будет, а геттером можно в принципе пожертвовать. Но в этом случае учтите, что финальность поля — часть контракта и вы не можете в будущем взять и убрать слово final: пользователи могут заложиться на то, что ваше поле нельзя неконтролируемо изменить.

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

Отправить комментарий