#новичкам
У нас есть 2 варианта, как мы можем наполнять объект данными.
1️⃣ Делаем все поля публичными, не определяем ни одного конструктор и используем агрегатную инициализацию
struct Order {
std::string client_id;
std::string item_id;
float amount;
};
Example ex = {"123", "1234", 42.0};2️⃣ Делаем конструктор и заполняем приватные поля в нем
class Clock {
int hour, minute;
public:
Clock(int h, int m) : hour(h), minute(m) {
...
}
};
auto cl = Clock(12, 34)Как понять, какой вариант выбрать, когда в следующий раз придется писать новый класс? Будем разбираться
Для того, чтобы агрегатная инциализация была корректным способом создания объекта, должны быть выполнены некоторые условия:
👉🏿 Поля должны быть независимы друг от друга.
👉🏿 Поля должны иметь возможность представлять собой весь спектр значений своего типа.
👉🏿 Нет дополнительной логики, которая срабатывает на каждое создание объекта.
Эти 3 пункта гарантируют, что наш класс - это просто набор каких-то значений. Мы можем собрать этот набор частично, поменять содержимое по середине пути и ничего плохого не произойдет.
В противном же случае в вашем классе есть инвариант, который важно сохранять для каждого объекта.
Например, в объекте типа даты, который создается из строки, нужно проверять, валидная ли дата передана. В объекте типа математического интервала левый конец должен быть меньше либо равен правому. Или при создании какого-то объекта мы накручиваем счетчик из метрики.
И вот как раз для того, чтобы вся логика проверки и обеспечения инварианта объекта была внутри кода класса, а не в клиентском коде, нужно определять конструктор. Так детали реализации будут инкапсулированы внутрь класса. Это позволит абстрагироваться от них в клиентском коде и даже если логика инварианта изменится, то это никак не затронет внешний код.
class BufferView {
const char* data;
size_t size;
public:
BufferView(const char* ptr, size_t len) : data(ptr), size(len) {
if (size > 0 && data == nullptr)
throw std::runtime_error("BufferView error: nonzero size while data is nullptr");
}
};Странно было бы на пользователя возлагать ответственность за проверку соответствия размера и содержимого буфера. Они ведь такие безответственные.
Ну и в будущем, если мы захотим запретить вообще передавать в буффер nullptr, то это изменение коснется только кода класса.
Don't give details to a client. Stay cool.
#design #goodpractice