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

Должен ли я использовать общедоступные или частные переменные?

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

Я решил переписать этот код, чтобы использовать в основном только один тип. Но я не знаю, что я должен использовать (переменные, которые используются только для методов в одном и том же объекте, всегда являются частными и не подлежат этому вопросу).

Я знаю теорию, что означает общественность и личность, но что используется в реальном мире и почему?

4b9b3361

Ответ 1

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

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

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

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

Это, конечно, эмпирическое правило - например, я бы просто использовал struct (эквивалент с class с открытым доступом), например, для простого класса точек:

struct Point2D
{
   double x;
   double y;
};

Ответ 2

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

Представьте, что у вас есть класс Truck в логистическом проекте:

class Truck {
public:
    double capacity;

    // lots of more things...
};

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

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

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

С подходом, описанным выше, это будет означать большую работу, вам придется отслеживать все виды использования Truck::capacity и решать, что с ними делать. Это, вероятно, означает изменение файлов по всей базе кода. Предположим, в качестве альтернативы, что вы решили более подход theoretic.

class Truck {
public:
    double getCapacity() const
        { return capacity; }

    // lots of more things...
private:
    double capacity;
};

Возможное альтернативное изменение не включает модификацию интерфейса класса:

class Truck {
public:
    double getCapacity() const
        { if ( Configuration::Measure == Gallons ) {
            return capacity;
          } else {
             return ( capacity * 3.78 );
          }
        }


    // lots of more things...
private:
    double capacity;
};

(Пожалуйста, возьмите int account, что есть много способов сделать это, что это только одна возможность, и это только пример)

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

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

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

Ответ 3

Нет жесткого правила в отношении того, что должно быть закрытым/общедоступным или защищенным.

Это зависит от роли вашего класса и того, что он предлагает.

  • Все методы и члены, которые составляют внутреннюю работу класс должен быть сделан private.
  • Все, что класс предлагает внешнему миру, должен быть общедоступным.
  • Члены и методы, которые могут быть расширены по специализации этого класса, может быть объявлено как protected.

Ответ 4

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

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

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

Код С++ обычно не использует геттеры/сеттеры, когда они не обеспечивают реальный выигрыш. Если вы разрабатываете проект на 1000 000 строк с большим количеством модулей, которые должны быть как можно более независимыми, это может иметь смысл, но для большинства нормальных кодов, которые вы пишете каждый день, они переполняются.

Ответ 5

Существуют некоторые типы данных, единственная цель которых заключается в сохранении четко определенных данных. Обычно они могут быть написаны как структуры с общедоступными элементами данных. Помимо этого, класс должен определять абстракцию. Публичные переменные или тривиальные сеттеры и геттеры предполагают, что дизайн не продуман достаточно, что приводит к агломерации слабых абстракций, которые не абстрагируют многое из чего-либо. Вместо того, чтобы думать о данных, подумайте о поведении: этот класс должен делать X, Y и Z. Оттуда решить, какие внутренние данные необходимы для поддержки желаемого поведения. Сначала это не так просто, но напоминайте себе, что это поведение важно, а не данные.

Ответ 6

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

private int var;

public int getVar() {
  return var;
}

public void setVar(int _var) {
  var = _var;
}

Современные IDE, такие как Eclipse и другие, помогут вам сделать это, предоставив такие функции, как "Реализовать Getters и Setters" и "Encapsulate Field" (который заменяет все прямые acccesses переменных соответствующими вызовами getter и setter).

Ответ 7

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

Другим преимуществом getters и seters является то, что если вы используете IDE (например, Eclipse или Netbeans), вы можете использовать функциональность IDE для поиска каждого места в кодовой базе, где вызывается функция, Они обеспечивают видимость того, где часть данных в этом конкретном классе используется или модифицируется. Кроме того, вы можете легко сделать доступ к потоковым переменным-членам, используя внутренний мьютекс. Функции getter/setter будут захватывать этот мьютекс перед доступом или изменением переменной.

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