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

Доступ к членам напрямую или всегда с использованием геттеров

Примечание: С++ конкретный вопрос

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

EDIT основан на многих умных комментариях:

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

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

Ответ 3

ОБЫЧНЫЙ

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

getters и seters для частных членов редко являются чистым преимуществом:

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

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

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

НЕ-СОБЫТОЕ

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

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

Ответ 4

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

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

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

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

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

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();
}

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

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(){}

EDIT:

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

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

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

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

Ответ 11

Мои мысли следующие.

Все должно быть статичным, постоянным и приватным, если это возможно.

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

  • Так как вам нужна переменная для изменения, вы удалите const.

  • Поскольку вам нужен класс/переменная для доступа других классов, вы удаляете приватный.

Использование сеттеров/геттеров - общего назначения.

  • Getter в порядке, если значение ТОЛЬКО будет изменено классом, и мы хотим его защитить. Таким образом, мы можем получить текущее состояние этого значения без возможности изменения его значения.
  • Getter не следует использовать, если вы планируете предоставить Setter вместе с ним. На этом этапе вы должны просто преобразовать значение в public и просто изменить его напрямую. Так как это намерение с Get/Set.

  • Сеттер совершенно бесполезен, если вы планируете делать больше, чем просто "this.value = value". Тогда вам не следует называть его "SetValue", а описывать, что он на самом деле делает.

  • Если, скажем, вы хотите внести изменения в значение, прежде чем "ПОЛУЧИТЬ" его значение. Тогда НЕ называйте это "GetValue". Это двусмысленно для вашего намерения, и хотя вы, возможно, знаете, что происходит. Кто-то другой не будет, если они не просмотрели исходный код этой функции.

  • Если, скажем, вы действительно только получаете/устанавливаете значение, но вы делаете некоторую форму безопасности. Т.е. проверка размера, проверка нуля и т.д. - это альтернативный сценарий. Однако вы все равно должны уточнить, что в имени, например, "SafeSetValue", "SafeGetValue" или как в "printf", есть "printf_s".

Альтернативы ситуациям Get/Set

  • Пример, который я лично имею. Что вы можете увидеть, как я справляюсь со сценарием Get/Set. Есть ли у меня класс GameTime, в котором хранятся все виды значений, и каждый тик игры изменяет эти значения.

    https://github.com/JeremyDX/DX_B/blob/master/DX_B/GameTime.cpp

  • Как вы увидите выше, мои "ПОЛУЧАЕТ" на самом деле не "ПОЛУЧАЕТ"
    значения, за исключением небольших случаев, когда изменение не требуется. Скорее, это описания ценностей, которые я пытаюсь извлечь из этого.
    Класс GameTime. Каждое значение является "Статическим Частным". Я не могу сделать конст
    учитывая информацию, полученную до времени выполнения, и я держу это
    статический, так как нет цели иметь несколько экземпляров Timing.

  • Как вы также увидите, у меня нет никакого способа выполнить "SET" для этих данных, но есть две функции "Begin()" и "Tick()", которые обе меняют значения. Вот как должны обрабатываться ВСЕ "сеттеры". По сути, функция "Begin()" сбрасывает все данные и загружает их в наши константы, которые мы НЕ можем установить как константы, поскольку это данные, которые мы получаем во время выполнения. Затем TICK() обновляет определенные значения с течением времени в этом случае, поэтому мы получаем свежую актуальную информацию.

  • Если вы посмотрите глубоко в код, вы найдете значения "ResetWindowFrameTime()" и "ElapsedFrameTicks()". Обычно я бы не стал делать что-то подобное и просто установил бы значение public. Поскольку, как вы увидите, я получаю значение и устанавливаю его. Это еще одна форма Set/Get, но она по-прежнему использует именование, соответствующее сценарию, и использует данные из частных переменных, поэтому не имеет смысла извлекать другую закрытую переменную, а затем умножать ее на это, вместо этого выполните работу здесь и извлеките результат. Также нет необходимости редактировать значение, отличное от того, чтобы сбросить его до текущего индекса кадра и затем извлечь истекшие кадры. Он используется, когда я открываю новое окно на моем экране, чтобы я мог знать, как долго я просматриваю это окно, и действовать соответственно.