Ostatnio zastanawiałem się nad wzorcem budowniczego bo już na kilku stronach widziałem, że przykłady ilustrują trochę inne podejście niż to jakie używam od zawsze. A mianowicie z poczciwą metodą build()
jako ostatnia metoda w łańcuchu metod. No to może przykłady.
Najpierw stary sposób:
#include <utility>
#include <string>
class Person;
class PersonBuilder {
friend class Person;
public:
PersonBuilder& setName(const std::string& name) { this->name = name; return *this; }
Person build();
private:
std::string name;
};
class Person {
public:
Person() = delete;
Person(const PersonBuilder& builder) : name(std::move(builder.name)) {}
private:
std::string name;
};
Person PersonBuilder::build() { return Person(*this); }
int main(int argc, char *argv[]) {
Person pereson = PersonBuilder().setName("Jan").build();
return 0;
}
Wariant starego sposobu:
#include <utility>
#include <string>
class Person {
friend class PersonBuilder;
private:
Person() = default;
public:
Person(const Person& person) = default;
private:
std::string name;
};
class PersonBuilder {
friend class Person;
public:
PersonBuilder& setName(const std::string& name) { person.name = name; return *this; }
Person build() { return std::move(person); }
private:
Person person;
};
int main(int argc, char *argv[]) {
Person person = PersonBuilder().setName("Jan").build();
return 0;
}
I w końcu nowy sposób nazywany na niektórych stronach Modern Builder Pattern (z operatorem rzutowania):
#include <utility>
#include <string>
class Person {
friend class PersonBuilder;
private:
Person() = default;
public:
std::string name;
};
class PersonBuilder {
public:
PersonBuilder& setName(const std::string& name) { person.name = name; return *this; }
operator Person&&() { return std::move(person); }
private:
Person person;
};
int main(int argc, char *argv[]) {
Person person = PersonBuilder().setName("Jan");
return 0;
}
Różnicę widać na pierwszy rzut oka. Zamiast wywoływać metodę build
i kopiować/przenosić dane za pomocą zdefiniowanego konstruktora lub konstruktora kopiującego to definiuje się operator rzutowania. Ale czy poza mechanizmem przenoszenia danych jest jeszcze jakaś ZNACZĄCA różnica. Zapis też jest krótszy bo nie używa się dodatkowej metody build()
ale osobiście to jestem do niej przyzwyczajony bo przynajmniej wiem, że budowanie się zakończyło.
Co o tym sądzicie? I której składni używacie?
pan_krewetekvpiotr