У меня есть класс с большим количеством встроенных членов типа с доступом для чтения/записи. Должен ли я сделать их публичными членами и предоставить методы get/set для каждого из них? Как насчет структур?
Аксессоры против публичных членов
Ответы (5)
Если есть инварианты, которые нужно сохранить, то да. В противном случае, не беспокойтесь.
Вся причина иметь аксессоры (геттеры) и модификаторы (сеттеры) состоит в том, чтобы обеспечить себе дополнительный уровень косвенности.
Этот дополнительный уровень косвенности позволяет вам предоставить общедоступному интерфейсу представление вашей переменной только для чтения, не позволяя изменять член данных. Вы все еще можете использовать частный или защищенный сеттер.
Сеттеры позволяют выполнять специальную проверку ошибок, проверку и исправление при установке значения. Например, setDirectory(const std::string &strPath), вы можете убедиться, что есть завершающая косая черта, если пользователь ее не указал. Это гарантирует, что ваше состояние класса всегда будет действительным.
Геттеры также могут защитить ваших членов от их раскрытия, чтобы разрешить указатели на них. Не допуская указателей на них извне, вы можете гарантировать, что если ваш объект выйдет за пределы области видимости, это не приведет к сбою.
Дополнительный уровень косвенности для геттеров/сеттеров также позволяет вам изменять элемент данных, который они инкапсулируют.
С помощью геттера вы также можете получить различные представления ваших данных, например: getMinutes, когда ваш элемент данных фактически хранится в секундах.
Это не причина их использования, но приятный побочный эффект использования геттеров и сеттеров заключается в том, что вы можете установить точку останова внутри своего модификатора, например, чтобы точно видеть, когда он изменяется.
Следует ли вам их использовать или нет, зависит от ваших потребностей. Если у вас так много членов, что предоставить геттеры и настройки очень сложно, вы можете рассмотреть возможность хранения членов данных в структуре и использования этой структуры внутри вашего класса. Вы даже можете предоставить геттеры/сеттеры для объекта сразу для всей структуры.
Во-первых, если в вашем классе много элементов данных, возможно, он плохо спроектирован. Возможно, вам придется подумать о разделении его на несколько классов или сохранении данных в таких структурах, как карты.
Что касается предоставления доступа, вопрос заключается в том, захотите ли вы когда-нибудь изменить доступ, возможно, предотвратив его. Если ответ да, то вам нужны функции доступа. С другой стороны, если ваш класс на самом деле просто набор битов без какого-либо поведения, сделайте его структурой.
Вы должны использовать только общедоступные данные
- в структурах, которые вы не подвергаете клиентскому коду (например, функторы в стиле связывания) - бесполезно защищать структуры, которые никто извне никогда не получит
- если их типы инкапсулируют логику их установки/получения (например, если вы создаете класс ObservableAttribute)
- если они являются константными членами в неизменной структуре (вы ничего не можете сделать, кроме как прочитать их, если они неизменяемы)
Если вы создаете общедоступный элемент данных, вы должны быть уверены, что его значение полностью ортогонально другим членам класса. Например, вы отключаете будущие возможности
- наблюдение за изменениями члена
- заставить член играть любую роль в инварианте класса
- отключение доступа к участнику
- изменение реализации члена (например, вычисляемый, кэшированный или хранимый), если это необходимо для производительности.
Использование методов get/set для закрытых/защищенных элементов данных — плохой дизайн.
Это заставляет клиентский код зависеть от деталей реализации вашего класса.
Изменения в вашем классе вызывают изменения в клиентском коде.
Однако можно использовать методы get/set для открытых членов. Но всегда лучше их избегать.