假设我们要创建一个Person类,Person类需要如下信息
// 地址信息
std::string street_address, post_code, city;
// 工作信息
std::string company_name, position;
int annual_income = 0;
设计一个足够炫酷的构造器,ta看起来像这样
Person p = Person::create()
.lives().at("123 London Road").with_postcode("SW1 1GB").in("London")
.works().at("PragmaSoft").as_a("Consultant").earning(10e6);
怎么做到的,首先我们创建了一个 PersonBuilderBase
类 定义如下
class PersonBuilderBase
{
protected:
Person& person;
explicit PersonBuilderBase(Person& person)
: person{ person }
{
cout << "PersonBuilderBase ctor, " << &person << endl;
}
public:
operator Person() const
{
return std::move(person);
}
// builder facets
PersonAddressBuilder lives() const;
PersonJobBuilder works() const;
};
看的出来构造函数是Protected
的,也就是说,他作为一个基类,不要直接去使用他,而是要让子类去继承。
我们设计了三个子类去继承 PersonBuilderBase
类。
分别是PersonJobBuilder
, PersonAddressBuilder
, PersonBuilder
出来PersonBuilderBase
的lives
方法和works
方法分别会返回前两个子类
其中 JobBuilder 构建工作相关的信息,AddressBuilder构建地址相关的信息
JobBuilder
class PersonJobBuilder : public PersonBuilderBase
{
typedef PersonJobBuilder Self;
public:
explicit PersonJobBuilder(Person& person)
: PersonBuilderBase { person }
{
}
Self& at(std::string company_name)
{
person.company_name = company_name;
return *this;
}
Self& as_a(std::string position)
{
person.position = position;
return *this;
}
Self& earning(int annual_income)
{
person.annual_income = annual_income;
return *this;
}
};
返回引用是为了支持流式操作
AddressBuilder
class PersonAddressBuilder : public PersonBuilderBase
{
typedef PersonAddressBuilder Self;
public:
explicit PersonAddressBuilder(Person& person)
: PersonBuilderBase{person}
{
}
Self& at(std::string street_address)
{
person.street_address = street_address;
return *this;
}
Self& with_postcode(std::string post_code)
{
person.post_code = post_code;
return *this;
}
Self& in(std::string city)
{
person.city = city;
return *this;
}
};
最后是PersonBuilder
class PersonBuilder : public PersonBuilderBase
{
Person p;
public:
PersonBuilder(): PersonBuilderBase{p}
{
cout << "PersonBuilder ctor" << endl;
}
};
最后就可以像开头一样
Person p = Person::create()
.lives().at("123 London Road").with_postcode("SW1 1GB").in("London")
.works().at("PragmaSoft").as_a("Consultant").earning(10e6);
使用了,create显然是个静态方法,返回一个PersonBuilder
PersonBuilder Person::create()
{
return PersonBuilder{};
}
但是写这么复杂真的好吗?可能得等我遇到实际问题才知道了
总结与反思
- 为了使用户使用构造器,往往需要把原本被构造的对象的构造函数藏起来不让用
- 通常支持流式操作
- 构造器往往有的良好的语义性(值每个函数都清楚的解释了自己在干什么)
但是我觉得除非有良好的文档,要不然如何去构造一个对象都得去实际查看别人的代码,看看别人是怎么构造的。但是实际上就自己公司的代码来看,文档这东西属于稀罕物件。。。
构造器看上去确实挺优雅的,但是用不用,还是具体再说吧,毕竟设计模式并不是什么放之四海皆准的准则,只要大的方向没变就好