Подтвердить что ты не робот

Публичные данные против Getters, Setters

В настоящее время я работаю в Qt и поэтому С++. У меня есть классы, в которых есть частные члены данных и функции публичных членов. У меня есть публичные получатели и сеттеры для членов данных, доступных в классе.

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

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

4b9b3361

Ответ 1

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

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

EDIT: после комментария я сделал другой ответ.

Моя точка зрения заключается в том, что вы задаете неправильный вопрос. Не существует наилучшей практики использования геттеров/сеттеров или имеющих публичных членов. Существует только то, что лучше всего подходит для вашего конкретного объекта и как он моделирует некоторые конкретные вещи реального мира (или мнимые вещи, возможно, в случае игры).

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

Вместо этого изучите, что делает объект и что значит для чего-то быть тем объектом. Затем создайте методы, которые обеспечивают естественный интерфейс в этом объекте. Это, что естественный интерфейс включает в себя выявление некоторых внутренних свойств с использованием геттеров и сеттеров, так и быть им. Но важная часть заключается в том, что вы задумались об этом заранее и создали геттеры/сеттеры по обоснованной причине дизайна.

Ответ 2

Нет, это даже не отдаленно одно и то же.

Существуют разные уровни защиты/реализации, которые могут быть достигнуты с помощью различных подходов к интерфейсу класса:


1. Открытый элемент данных:

  • предоставляет как чтение, так и запись (если не const) доступ к элементу данных
  • раскрывает тот факт, что объект данных физически существует и физически является членом этого класса (позволяет создавать указатели типа указатель-член для этого элемента данных)
  • предоставляет lvalue доступ к элементу данных (позволяет создавать обычные указатели для элемента)


2. Метод, который возвращает ссылку на часть данных (возможно, на частный элемент данных):

  • предоставляет как чтение, так и запись (если не const) доступ к данным
  • раскрывает тот факт, что объект данных физически существует, но не раскрывает, что он физически является членом этого класса (не позволяет создавать указатели типа указатель-член для данных)
  • обеспечивает доступ к данным lvalue (позволяет создавать для него обычные указатели)


3. Методы Getter и/или setter (возможно, доступ к частному элементу данных):

  • предоставляет как доступ для чтения, так и/или записи к свойству
  • не раскрывает тот факт, что объект данных физически существует, не говоря уже о физическом присутствии в этом классе (не позволяет создавать указатели типа указателя на член для этих данных или любого вида указателей в этом отношении)
  • не предоставляет lvalue доступ к данным (не позволяет создавать обычные указатели)

Подход геттера/сеттера даже не раскрывает тот факт, что свойство реализуется физическим объектом. То есть не может быть физического элемента данных за парой getter/setter.

Принимая во внимание вышеизложенное, странно видеть, что кто-то утверждает, что пара геттеров и сеттеров совпадает с общим элементом данных. Фактически, у них нет ничего общего.

Конечно, есть вариации каждого подхода. Например, метод getter может возвращать константную ссылку на данные, которая помещает ее где-то между (2) и (3).

Ответ 3

Если у вас есть получатели и сеттеры для каждого из ваших элементов данных, нет смысла делать данные конфиденциальными. Поэтому наличие геттеров и сеттеров для каждого из ваших элементов данных - плохая идея. Рассмотрим класс std::string - он (возможно) имеет ONE getter, функцию size() и вообще не устанавливает.

Или рассмотрим объект BankAccount - нужно ли нам устанавливать SetBalance() setter для изменения текущего баланса? Нет, большинство банков не поблагодарит вас за реализацию такой вещи. Вместо этого нам нужно что-то вроде ApplyTransaction( Transaction & tx ).

Ответ 4

Getters and Setters позволяют применять логику для ввода/вывода от частных членов, следовательно, контролируя доступ к данным (инкапсуляция тем, кто знает их термины OO).

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

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

Помните, что это не означает, что каждая и каждая частная переменная нуждается в собственном getter/setter. Нейл поднимает хороший момент в своем банковском примере, что иногда Getters/Setters просто не имеют смысла.

Ответ 5

Сделайте данные общедоступными. В (весьма маловероятном) событии, которое вам когда-нибудь понадобится логика в "getter" или "setter", вы можете изменить тип данных на прокси-класс, который перегружает operator= и/или operator T (где T = любой тип вы используете сейчас) для реализации необходимой логики.

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

Инкапсуляция дополняет абстракцию: абстракция имеет дело с внешне видимым поведением объекта, в то время как инкапсуляция имеет дело со скрытием деталей того, как это поведение реализовано.

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

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

Ответ 6

Если вы совершенно уверены, что ваша логика проста, и вам никогда не нужно делать что-то еще при чтении/записи переменной, лучше хранить данные публично. В случае С++ я предпочитаю использовать struct вместо класса, чтобы подчеркнуть тот факт, что данные являются общедоступными.

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

Простой пример дополнительной функциональности - вы можете регистрировать строку отладки при каждом доступе к переменной.

Ответ 7

Помимо проблем с инкапсуляцией (которые являются достаточной причиной), очень легко установить точку останова всякий раз, когда переменная устанавливается/доступна, когда у вас есть получатели/сеттеры.

Ответ 8

На строго практической основе я предлагаю вам начать с того, что все ваши данные будут закрытыми, и сделайте их получателями и сеттерами конфиденциальными. Когда вы узнаете, что на самом деле нужен всему миру (т.е. Ваше сообщество пользователей (l) ", вы можете выявить соответствующие геттеры и/или сеттеры или написать подходящие публичные устройства доступа.

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

Ответ 9

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

Ответ 10

Причины использования публичных полей, а не геттеров и сеттеров, включают:

  • Нет никаких незаконных значений.
  • Ожидается, что клиент отредактирует его.
  • Чтобы писать такие вещи, как object.X.Y = Z.
  • Чтобы обещать, что значение является просто значением, и никаких связанных с ним побочных эффектов (и не будет и в будущем).

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

(Из Десять вопросов по ценностному программированию.)

Ответ 11

Я предлагаю, чтобы у вас не было публичных элементов данных (кроме структур POD). Я также не рекомендую, чтобы у вас были получатели и сеттеры для всех ваших членов данных. Скорее, определите чистый публичный интерфейс для своего класса. Это может включать методы, которые получают и/или задают значения свойств, и эти свойства могут быть реализованы как переменные-члены. Но не делайте геттеры и сеттеры для всех ваших членов.

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

Ответ 12

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

Рассмотрим следующее:

double premium;
double tax;

Затем вы пишете код по всему месту, используя это значение premium, чтобы получить премию:

double myPremium = class.premium;

Ваши спецификации просто изменились, а премия с точки зрения пользователя должна быть premium + tax

Вам нужно будет изменить везде, что это значение premium используется в вашем коде, и добавьте tax к нему.

Если вместо этого вы внедрили его как таковое:

double premium;
double tax;

double GetPremium(){return premium;};

Весь ваш код будет использовать GetPremium(), а ваше изменение tax будет одной строкой:

double premium;
double tax;

double GetPremium(){return premium + tax;};

Ответ 13

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

Ответ 14

Getters и Setters существуют прежде всего для того, чтобы мы могли контролировать, как выбираются участники, и как они установлены. Геттеры и сеттеры не существуют только как способ доступа к определенному члену, но чтобы убедиться, что перед тем, как мы попытаемся установить член, возможно, он соответствует определенным условиям или, если мы его извлечем, мы могли бы контролировать, что мы возвращаем копию этого член в случае непримитивного типа. В общем, вы должны попробовать и использовать g/s'ers, когда хотите конвейеру, каким образом должен взаимодействовать элемент данных, без них это приведет к тому, что элемент будет использоваться в adhoc.

Ответ 15

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

В качестве ссылки прочитайте рекомендации С++ (C.131)