设计模式: 组合构造器

本文介绍了如何通过设计模式创建一个可读性强的Person类构造器,利用PersonBuilderBase、PersonJobBuilder和PersonAddressBuilder子类实现流式操作,虽然优雅但需配合良好文档,设计模式并非通用准则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设我们要创建一个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类。

分别是PersonJobBuilderPersonAddressBuilderPersonBuilder
出来PersonBuilderBaselives方法和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{};
}

但是写这么复杂真的好吗?可能得等我遇到实际问题才知道了

总结与反思

  1. 为了使用户使用构造器,往往需要把原本被构造的对象的构造函数藏起来不让用
  2. 通常支持流式操作
  3. 构造器往往有的良好的语义性(值每个函数都清楚的解释了自己在干什么)

但是我觉得除非有良好的文档,要不然如何去构造一个对象都得去实际查看别人的代码,看看别人是怎么构造的。但是实际上就自己公司的代码来看,文档这东西属于稀罕物件。。。
构造器看上去确实挺优雅的,但是用不用,还是具体再说吧,毕竟设计模式并不是什么放之四海皆准的准则,只要大的方向没变就好

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值