设计模式之建造者
问题:构造函数参数太多(「伸缩构造」),或步骤必须按顺序、且步骤组合多变。
做法:Director(可选)规定步骤顺序;Builder提供setA()、setB()… 最后build()返回产品。
C++ 要点:
- 很多场景用 fluent interface(链式
builder.withX().withY())提高可读性。 - 若只是「很多默认可选参数」,也可以先评估 默认成员 + 结构体选项 或 命名参数 idiom(C++ 没有命名参数,用小的
struct Options很常见),不必一上来上完整 Builder。
// C++17:建造者(Builder) // 要点:把复杂对象的构造拆成多步,可读、可校验;可与 Director 搭配固定几种装配顺序。 #include <iostream> #include <memory> #include <optional> #include <sstream> #include <stdexcept> #include <string> #include <unordered_map> #include <utility> // ---------- 产品:字段多、组合多,不适合巨型构造函数 ---------- class HttpRequest { public: const std::string& url() const { return url_; } const std::string& method() const { return method_; } const std::unordered_map<std::string, std::string>& headers() const { return headers_; } const std::optional<std::string>& body() const { return body_; } std::string describe() const { std::ostringstream os; os << method_ << " " << url_ << "\n"; for (const auto& [k, v] : headers_) { os << " " << k << ": " << v << "\n"; } if (body_.has_value()) { os << " [body] " << *body_ << "\n"; } return os.str(); } private: friend class HttpRequestBuilder; HttpRequest() = default; std::string url_; std::string method_{"GET"}; std::unordered_map<std::string, std::string> headers_; std::optional<std::string> body_; }; // ---------- 建造者:流式 API,最后 build() 一次性产出 ---------- class HttpRequestBuilder { public: HttpRequestBuilder& set_url(std::string url) { url_ = std::move(url); return *this; } HttpRequestBuilder& set_method(std::string method) { method_ = std::move(method); return *this; } HttpRequestBuilder& add_header(std::string key, std::string value) { headers_.insert_or_assign(std::move(key), std::move(value)); return *this; } HttpRequestBuilder& set_body(std::string body) { body_ = std::move(body); return *this; } HttpRequest build() const { if (url_.empty()) { throw std::invalid_argument("HttpRequest: url 不能为空"); } HttpRequest req; req.url_ = url_; req.method_ = method_; req.headers_ = headers_; req.body_ = body_; return req; } private: std::string url_; std::string method_{"GET"}; std::unordered_map<std::string, std::string> headers_; std::optional<std::string> body_; }; // ---------- Director(可选):封装常用装配流程 ---------- class ApiClientDirector { public: static HttpRequest simple_get(std::string url) { return HttpRequestBuilder{}.set_url(std::move(url)).build(); } static HttpRequest json_post(std::string url, std::string json) { return HttpRequestBuilder{} .set_url(std::move(url)) .set_method("POST") .add_header("Content-Type", "application/json") .set_body(std::move(json)) .build(); } }; int main() { HttpRequest a = HttpRequestBuilder{} .set_url("https://api.example.com/v1/users") .set_method("GET") .add_header("Accept", "application/json") .add_header("Authorization", "Bearer ***") .build(); std::cout << "自定义 GET:\n" << a.describe() << "\n"; HttpRequest b = ApiClientDirector::json_post( "https://api.example.com/v1/login", R"({"user":"alice","pass":"secret"})"); std::cout << "Director POST:\n" << b.describe() << "\n"; try { (void)HttpRequestBuilder{}.build(); } catch (const std::exception& ex) { std::cout << "校验: " << ex.what() << "\n"; } return 0; }