Я делаю большой проект впервые. У меня есть много классов, и некоторые из них имеют открытые переменные, некоторые имеют закрытые переменные с методами set и getter и оба имеют оба типа.
Я решил переписать этот код, чтобы использовать в первую очередь только один тип. Но я не знаю, какие мне следует использовать (переменные, которые используются только для методов в одном и том же объекте, всегда закрыты и не являются предметом этого вопроса).
Я знаю теорию, что означает публичное и частное, но что используется в реальном мире и почему?
private
члены данных, как правило, считаются хорошими, потому что они обеспечивают инкапсуляцию.
Предоставление геттеров и сеттеров для них нарушает инкапсуляцию, но все же лучше, чем public
члены данных, потому что есть только одна точка доступа к этим данным.
Вы заметите это во время отладки. Если это личное, вы знать Вы можете изменить только переменную внутри класса. Если это общедоступно, вам придется искать всю базу кода, где это может быть быть изменены.
Насколько возможно, забаньте получателей / установщиков и создайте свойства private
, Это следует принципу сокрытия информации — вам не нужно заботиться о свойствах класса. Это должно быть автономным. Конечно, на практике это неосуществимо, и если это так, то проект, который следует этому, будет более загроможден и сложнее в обслуживании, чем тот, который этого не делает.
Это, конечно, практическое правило — например, я бы просто использовал struct
(эквивалентно class
с публичным доступом) для, скажем, простого точечного класса:
struct Point2D
{
double x;
double y;
};
Поскольку вы говорите, что знаете теорию, а другие ответы вникли в значение public / private, getter и setters, я бы хотел сосредоточиться на том, почему использовать аксессоры вместо создания публичных атрибутов (данные членов в C ++) ,
Представьте, что у вас есть класс 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;
};
(Пожалуйста, примите во внимание, что есть много способов сделать это, что есть только одна возможность, и это только пример)
Вам нужно будет создать глобальную конфигурацию класса утилит (но вы все равно должны были это сделать) и добавить включение в truck.h
за configuration.h
, но это все локальные изменения, остальная часть вашей кодовой базы остается неизменной, что позволяет избежать потенциальных ошибок.
Наконец, вы также заявляете, что сейчас работаете над большим проектом, который, я думаю, является той областью, в которой эти причины на самом деле имеют больше смысла. Помните, что цель, о которой следует помнить при работе в больших проектах, заключается в создании поддерживаемого кода, то есть кода, который вы можете исправлять и расширять новыми функциями. Вы можете забыть о геттерах и сеттерах в личных небольших проектах, хотя я постараюсь привыкнуть к ним.
Надеюсь это поможет.
Не существует жесткого правила относительно того, что должно быть частным / публичным или защищенным.
Это зависит от роли вашего класса и того, что он предлагает.
С точки зрения ООП геттеры / сеттеры помогают с инкапсуляцией и поэтому должны всегда использоваться. Когда вы вызываете метод получения / установки, класс может делать все, что он хочет, за кулисами, и внутренняя часть класса не подвергается воздействию извне.
С другой стороны, с точки зрения C ++, это также может быть недостатком, если класс делает много неожиданных вещей, когда вы просто хотите получить / установить значение. Людям нравится знать, приводит ли какой-либо доступ к огромным накладным расходам или является простым и эффективным Когда вы обращаетесь к публичной переменной, вы точно знаете, что вы получаете, когда вы используете метод получения / установки, вы понятия не имеете.
Особенно, если вы выполняете только небольшой проект, тратя свое время на написание геттеров / сеттеров и корректируя их все соответственно, когда вы решаете изменить имя переменной / тип / …, вы получаете много занятой работы за небольшую выгоду. Тебе лучше потратить это время на написание кода, который делает что-то полезное.
Код C ++ обычно не использует геттеры / сеттеры, когда они не дают реальной выгоды. Если вы разрабатываете проект из 1 000 000 строк с большим количеством модулей, которые должны быть настолько независимыми, насколько это возможно, это может иметь смысл, но для большинства кода нормального размера вы пишете изо дня в день, это излишне.
Есть некоторые типы данных, единственной целью которых является хранение четко определенных данных. Обычно они могут быть записаны как структуры с открытыми членами данных. Кроме того, класс должен определять абстракцию. Публичные переменные или тривиальные сеттеры и геттеры предполагают, что дизайн не был достаточно продуман, что приводит к скоплению слабых абстракций, которые ничего не абстрагируют. Вместо того, чтобы думать о данных, подумайте о поведение: этот класс должен выполнять X, Y и Z. Оттуда решить, какие внутренние данные необходимы для поддержки желаемого поведения. Поначалу это нелегко, но продолжайте напоминать себе, что важно поведение, а не данные.
Публичные переменные обычно не рекомендуется, и лучшая форма — сделать все переменные приватными и получить к ним доступ с помощью методов получения и установки:
private int var;
public int getVar() {
return var;
}
public void setVar(int _var) {
var = _var;
}
Современные IDE, такие как Eclipse и другие, помогают вам в этом, предоставляя такие функции, как «Реализация методов получения и установки» и «Инкапсуляция поля» (которая заменяет все прямые обращения к переменным соответствующими вызовами получения и установки).
Частные переменные-члены предпочтительнее открытых переменных-членов, главным образом по причинам, указанным выше (инкапсуляция, точные данные и т. Д.). Они также обеспечивают некоторую защиту данных, поскольку гарантируют, что ни одна внешняя сущность не сможет изменить переменную-член, не пройдя через надлежащий канал установщика, если это будет необходимо.
Еще одним преимуществом методов получения и установки является то, что если вы используете IDE (например, Eclipse или Netbeans), вы можете использовать функциональные возможности IDE для поиска каждый место в кодовой базе, где вызывается функция. Они обеспечивают видимость того, где часть данных в этом конкретном классе используется или модифицируется. Кроме того, вы можете легко сделать доступ к переменным-членам потокобезопасным, имея внутренний мьютекс. Функции getter / setter будут захватывать этот мьютекс перед доступом к переменной или ее изменением.
Я сторонник абстракции до такой степени, что это все еще полезно. Абстракция ради абстракции обычно приводит к беспорядочному беспорядку, который является более сложным, чем его ценность.