使用Builder / Fluent模式最小化所需的头文件数量

时间:2018-02-21 00:04:07

标签: c++ design-patterns pimpl-idiom

我正在尝试使用Builder / Fluent风格创建对象,试图扩展课程中提出的一些想法。我立即对我的测试实现不喜欢的一个要素是客户端需要包含的大量额外头文件才能使进程工作,特别是当我希望通过pImpl惯用法使用公共/私有头时提供库接口的目的。我不完全确定问题是由于我的实施还是我错过了一个明显的最后一步'实现我想要的。

一般要点如下(使用飞行员的玩具示例):

首先是客户代码本身:
注意:为简洁起见,省略了各种样板和无关代码)

Pilot p = Pilot::create()
        .works().atAirline("Sun Air").withRank("Captain")
        .lives().atAddress("123 Street").inCity("London")

这里发生的事情是:

  • Pilot.h 中,Pilot类使用名为create()的静态成员方法定义,该方法返回<1}中定义的PilotBuilder类的实例strong> PilotBuilder.h 并在 Pilot.h
  • 中声明转发
  • 基本上PilotBuilder类是一个便利构建器,仅用于显示Pilot(.works().lives())的两个不同方面的构建器,让您从一个构建器切换到另一个构建器

Pilot.h:

class PilotBuilder;
class Pilot {
private:
    // Professional
    string airline_name_, rank_;    

    // Personal
    string street_address_, city_;

    Pilot(){}
public:
    Pilot(Pilot&& other) noexcept;

    static PilotBuilder create();

    friend class PilotBuilder;
    friend class PilotProfessionalBuilder;
    friend class PilotPersonalBuilder;
};

Pilot.cpp:

#include "PilotBuilder.h"

    PilotBuilder Pilot::create() {

        return PilotBuilder();
    }

    // Other definitions etc

PilotBuilder.h

#include "public/includes/path/Pilot.h"

class PilotProfessionalBuilder;
class PilotPersonalBuilder;

class PilotBuilder {    
private:
    Pilot p;
protected:
    Pilot& pilot_;

    explicit PilotBuilder(Pilot& pilot) : pilot_{pilot} {};

public:
    PilotBuilder() : pilot_{p} {}

    operator Pilot() {
        return std::move(pilot_);
    }

    PilotProfessionalBuilder works();
    PilotPersonalBuilder lives();
};

PilotBuilder.cpp

#include "PilotBuilder.h"
#include "PilotProfessionalBuilder.h"
#include "PilotPersonalBuilder.h"

PilotPersonalBuilder PilotBuilder::lives() {
   return PilotPersonalBuilder{pilot_};
}

PilotProfessionalBuilder PilotBuilder::works() {
    return PilotProfessionalBuilder{pilot_};
}

您可以想象PilotProfessionalBuilder类和PilotPersonalBuilder类只使用{提供的引用 - 以流畅的方式实现与该特定方面相关的方法,例如(.atAirline()) {1}}类,它们的实现与我的查询无关。
避免提供私人会员参考的轻微争议问题,我的困境是,为了充分利用我的模式,客户必须看起来像这样:

PilotBuilder

我无法弄清楚的是:

  1. 如何重新排序或重新实现代码,以便我可以在客户端中简单地使用#include "public/includes/path/Pilot.h" #include "private/includes/path/PilotBuilder.h" #include "private/includes/path/PilotProfessionalBuilder.h" #include "private/includes/path/PilotPersonalBuilder.h" int main() { Pilot p = Pilot::create() .works().atAirline("Sun Air").withRank("Captain") .lives().atAddress("123 Street").inCity("London"); } ,想象一下,我将链接到#include "public/includes/path/Pilot.h"库,其余的实现居住并仍然保持相同的行为?
  2. 如果有人可以在第1点启发我,那么有没有办法可以将Pilots的私人成员移动到Pilot并仍然保持静态{{1 }} 方法? - 因为显然不允许以下内容:
  3. unique_ptr<Impl> pImpl

    最后,我绝不是这方面的专家,所以如果我的任何术语不正确或编码实践真的需要修复,我会很乐意接受人们必须给出的任何建议。谢谢!

0 个答案:

没有答案