Доступ к членам напрямую или всегда использовать геттеры - PullRequest
18 голосов
/ 27 сентября 2010

Примечание: специфический вопрос C ++

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

Обновление: я имею в виду простых получателей, специально для класса ' непубличных членов.

Ответы [ 11 ]

12 голосов
/ 27 сентября 2010

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

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

12 голосов
/ 27 сентября 2010

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

РЕДАКТИРОВАТЬ на основе многих умных комментариев:

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

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

8 голосов
/ 27 сентября 2010

ОБЗОР

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

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

  • обеспечивает такие же преимущества инкапсуляции

    • единое место для точек останова / ведения журнала get / set + инвариантных проверок во время dev (если используется последовательно)
    • виртуальный потенциал
    • и т.д ...

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

НЕ ТАК ОБЗОР

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

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

5 голосов
/ 27 сентября 2010

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

Я бы не стал использовать getter и setter для доступа к собственным членам класса.

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

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

Для внешнего интерфейса я строго придерживаюсь открытого интерфейса; все переменные являются частными, и я избегаю friend за исключением перегрузок операторов; Я использую protected членов консервативно, и они считаются общедоступным интерфейсом. Однако даже для общедоступного интерфейса я обычно избегаю использования методов прямого получения и установки, поскольку они часто указывают на плохой дизайн ОО (каждый программист на любом языке должен читать: Почему методы получения и установки являются злыми ). Вместо этого у меня есть методы, которые делают что-то полезное, а не просто выборку значений. Например:

class Rectangle {
    private:
        int x, y, width, height;
    public:
        // avoid getX, setX, getY, setY, getWidth, setWidth, getHeight, setHeight
        void move(int new_x, int new_y);
        void resize(int new_width, int new_height);
        int area();
}
4 голосов
/ 27 сентября 2010

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

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

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

2 голосов
/ 27 сентября 2010

это на самом деле для поддержки объектно-ориентированного класса путем абстрагирования способа получения (getter).и просто обеспечивая его более легкий доступ.

2 голосов
/ 27 сентября 2010

Просто грубый пример.Помогает ли это?

struct myclass{
    int buf[10];
    int getAt(int i){
        if(i >= 0 && i < sizeof(buf)){
            return buf[i];
        }
    }

    void g(){
        int index = 0;
        // some logic
        // Is it worth repeating the check here (what getAt does) to ensure
              // index is within limits
        int val = buf[index];
    }
};

    int main(){}

РЕДАКТИРОВАТЬ:

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

2 голосов
/ 27 сентября 2010

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

1 голос
/ 27 сентября 2010

Простой ответ.Если вы пишете программу «один выстрел», которая никогда не изменится, вы можете оставить получателей в покое и обойтись без них.

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

Если вы используете методы получения, это поможет быстрее изменить код в дальнейшем, например, установить защиту для свойства для проверки правильности значения или подсчитать доступ к свойству (отладка).

Геттер для меня о легких возможностях (бесплатный обед).Программисту, который пишет код, не нужны геттеры, он хочет их.

надеюсь, что поможет.

1 голос
/ 27 сентября 2010

Защита переменной-члена путем обертывания ее доступа функциями get / set имеет свои преимущества. Однажды вы можете захотеть сделать ваш класс потокобезопасным - и в этом случае вы поблагодарите себя за использование этих функций get / set

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...