在C++中,构造器(Builder)模式的思考(《C++20设计模式》及常规设计模式对比)

文章目录

  • 一、前言
  • 二、为什么需要`Builder Pattern`,`Builder Pattern`到底解决了什么实际问题?为什么不用set()方法?
    • 2.1 初学者有那些对象的属性初始化方法呢?
      • 2.1.1 构造函数的弊端
        • 2.1.1.1 对于属性的初始化只能是固定的顺序
      • 2.1.2 用set()函数初始化类的弊端
        • 2.1.2.1 类属性太多,类的可读性太差
  • 三、`Builder Pattern`各种写法的对比
    • 3.1 《C++20设计模式》中的流式构造器
      • 3.1.1 流式构造器
        • 3.1.1.1 UML类图
        • 3.1.1.2 实现
    • 3.2 传统构造器
      • 3.2.1 UML类图
      • 3.2.2实现
    • 3.3 组合构造器
      • 3.3.1UML类图
      • 3.3.2实现
  • 四、总结

一、前言

笔者时刚学习Builder Pattern,遇到了很多问题,在此汇总一下,也希望能帮到你,如有错误请指正。

  • 为什么需要Builder Pattern,Builder Pattern到底解决了什么实际问题?为什么不用set()方法?
  • 《C++20:设计模式》流式构造器到底怎么实现的?friend关键字的使用是否必要?
  • 常规的构造器怎么实现?他能解决的问题?
  • 组合构造器的实现?

相关代码可以在这里,如有帮助给个star!AidenYuanDev/design_patterns_in_modern_Cpp_20

二、为什么需要Builder Pattern,Builder Pattern到底解决了什么实际问题?为什么不用set()方法?

首先明确一个点,Builder Pattern主要是对于对象的属性初始化的研究,也就是我们怎么样的方式创建对象才能高内聚,低耦合,实现更优雅。

2.1 初学者有那些对象的属性初始化方法呢?

  1. 使用构造函数 —— 属性的初始化只能是固定的顺序
  2. 创建set()函数初始化函数 —— 类属性太多,类的可读性太差

2.1.1 构造函数的弊端

2.1.1.1 对于属性的初始化只能是固定的顺序

重载的特性:如果一个构造函数的参数个数,参数类型,参数顺序一致的话就说他是同一个构造函数

举个例子:

class monster {
public:
	// 这两个构造函数是不能同时出现的,编译器会认为他们是同一个函数。
	monster(string name, int attack_damage, int defense) {
		_name = name;
		_attack_damage = attack_damage;
		_defense = defense;
	}
	
/*
	monster(string name, int defense, int attack_damage) {
		_name = name;
		_attack_damage = attack_damage;
		_defense = defense;
	}
*/
	
private:
	string _name;
	int _attack_damage;		// 攻击力
	int _defense;			// 防御力
};

所以说要想按任意顺序初始化类的属性,该怎么办呢?没错可以用set()方法

2.1.2 用set()函数初始化类的弊端

2.1.2.1 类属性太多,类的可读性太差

注:这里用了流式(也就是返回类自己的指针,主要简化main中初始化过程)
举个例子:

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>

class Vehicle {
private:
    // 基本属性
    std::string make;
    std::string model;
    int year;
    double price;

    // 动力属性
    double engineSize;
    int horsepower;
    std::string fuelType;

    // 尺寸和重量
    double length;
    double width;
    double height;
    double curbWeight;

    // 车辆特征
    std::vector<std::string> features;
    std::map<std::string, std::string> specifications;
    std::set<std::string> safetyFeatures;

    // 拥有者信息
    std::list<std::string> previousOwners;
    std::map<std::string, std::string> ownerDetails;

public:
    // 构造函数
    Vehicle(std::string make, std::string model, int year, double price)
        : make(make), model(model), year(year), price(price) {}

    // 流式设置方法
    Vehicle& setMake(const std::string &make) { this->make = make; return *this; }
    Vehicle& setModel(const std::string &model) { this->model = model; return *this; }
    Vehicle& setYear(int year) { this->year = year; return *this; }
    Vehicle& setPrice(double price) { this->price = price; return *this; }
    Vehicle& setEngineSize(double engineSize) { this->engineSize = engineSize; return *this; }
    Vehicle& setHorsepower(int horsepower) { this->horsepower = horsepower; return *this; }
    Vehicle& setFuelType(const std::string &fuelType) { this->fuelType = fuelType; return *this; }
    Vehicle& setLength(double length) { this->length = length; return *this; }
    Vehicle& setWidth(double width) { this->width = width; return *this; }
    Vehicle& setHeight(double height) { this->height = height; return *this; }
    Vehicle& setCurbWeight(double curbWeight) { this->curbWeight = curbWeight; return *this; }

    Vehicle& addFeature(const std::string &feature) { features.push_back(feature); return *this; }
    Vehicle& addSpecification(const std::string &key, const std::string &value) { specifications[key] = value; return *this; }
    Vehicle& addSafetyFeature(const std::string &feature) { safetyFeatures.insert(feature); return *this; }

    Vehicle& addPreviousOwner(const std::string &owner) { previousOwners.push_back(owner); return *this; }
    Vehicle& addOwnerDetail(const std::string &key, const std::string &value) { ownerDetails[key] = value; return *this; }

    // 获取属性的方法
    std::string getMake() const { return make; }
    std::string getModel() const { return model; }
    int getYear() const { return year; }
    double getPrice() const { return price; }
    double getEngineSize() const { return engineSize; }
    int getHorsepower() const { return horsepower; }
    std::string getFuelType() const { return fuelType; }
    double getLength() const { return length; }
    double getWidth() const { return width; }
    double getHeight() const { return height; }
    double getCurbWeight() const { return curbWeight; }
    std::vector<std::string> getFeatures() const { return features; }
    std::map<std::string, std::string> getSpecifications() const { return specifications; }
    std::set<std::string> getSafetyFeatures() const { return safetyFeatures; }
    std::list<std::string> getPreviousOwners() const { return previousOwners; }
    std::map<std::string, std::string> getOwnerDetails() const { return ownerDetails; }

    // 打印车辆信息的方法
    void printVehicleInfo() const {
        std::cout << "Make: " << make << "\nModel: " << model << "\nYear: " << year << "\nPrice: $" << price << "\n";
        std::cout << "Engine Size: " << engineSize << "L\nHorsepower: " << horsepower << "\nFuel Type: " << fuelType << "\n";
        std::cout << "Dimensions (LxWxH): " << length << " x " << width << " x " << height << " meters\n";
        std::cout << "Curb Weight: " << curbWeight << " kg\n";
        
        std::cout << "Features:\n";
        for (const auto &feature : features) {
            std::cout << "- " << feature << "\n";
        }

        std::cout << "Specifications:\n";
        for (const auto &spec : specifications) {
            std::cout << spec.first << ": " << spec.second << "\n";
        }

        std::cout << "Safety Features:\n";
        for (const auto &safety : safetyFeatures) {
            std::cout << "- " << safety << "\n";
        }

        std::cout << "Previous Owners:\n";
        for (const auto &owner : previousOwners) {
            std::cout << "- " << owner << "\n";
        }

        std::cout << "Owner Details:\n";
        for (const auto &detail : ownerDetails) {
            std::cout << detail.first << ": " << detail.second << "\n";
        }
    }
};

int main() {
    Vehicle car("Toyota", "Camry", 2021, 24000);
    car.setEngineSize(2.5)
       .setHorsepower(203)
       .setFuelType("Gasoline")
       .setLength(4.88)
       .setWidth(1.84)
       .setHeight(1.45)
       .setCurbWeight(1495)
       .addFeature("Air Conditioning")
       .addFeature("Navigation System")
       .addSpecification("Transmission", "8-speed automatic")
       .addSpecification("Drivetrain", "FWD")
       .addSafetyFeature("ABS")
       .addSafetyFeature("Airbags")
       .addPreviousOwner("John Doe")
       .addOwnerDetail("Current Owner", "Jane Smith");

    car.printVehicleInfo();

    return 0;
}

三、Builder Pattern各种写法的对比

3.1 《C++20设计模式》中的流式构造器

流式构造器要明白他的意思要把它分成两部分:

  • 构造器:就是把set方法从原有的类中拿出来,建立一个新类,用这个新类构造原来的类,实现解耦。
  • 流式set()返回值不再是void,现在返回类的指针

3.1.1 流式构造器

  • 流式构造器重载Vehicle(),就可以省去返回build()步骤
  • 这里注意要把流式构造器设置为(友元),不然访问不了被造的类的私有成员函数。

    是否应该使用friend关键字,后面讨论(friend破坏类的封装,到底要不要用,应不应该用?)

3.1.1.1 UML类图

流式构造器UML类图

3.1.1.2 实现
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <memory>

class Vehicle {
private:
    // 基本属性
    std::string make;
    std::string model;
    int year;
    double price;

    // 动力属性
    double engineSize;
    int horsepower;
    std::string fuelType;

    // 尺寸和重量
    double length;
    double width;
    double height;
    double curbWeight;

    // 车辆特征
    std::vector<std::string> features;
    std::map<std::string, std::string> specifications;
    std::set<std::string> safetyFeatures;

    // 拥有者信息
    std::list<std::string> previousOwners;
    std::map<std::string, std::string> ownerDetails;

public:
    // 构造函数
    Vehicle(const std::string& make, const std::string& model, int year, double price)
        : make(make), model(model), year(year), price(price), engineSize(0), horsepower(0), length(0), width(0), height(0), curbWeight(0) {}

    // 打印车辆信息的方法
    void printVehicleInfo() const {
        std::cout << "Make: " << make << "\nModel: " << model << "\nYear: " << year << "\nPrice: $" << price << "\n";
        std::cout << "Engine Size: " << engineSize << "L\nHorsepower: " << horsepower << "\nFuel Type: " << fuelType << "\n";
        std::cout << "Dimensions (LxWxH): " << length << " x " << width << " x " << height << " meters\n";
        std::cout << "Curb Weight: " << curbWeight << " kg\n";
        
        std::cout << "Features:\n";
        for (const auto &feature : features) {
            std::cout << "- " << feature << "\n";
        }

        std::cout << "Specifications:\n";
        for (const auto &spec : specifications) {
            std::cout << spec.first << ": " << spec.second << "\n";
        }

        std::cout << "Safety Features:\n";
        for (const auto &safety : safetyFeatures) {
            std::cout << "- " << safety << "\n";
        }

        std::cout << "Previous Owners:\n";
        for (const auto &owner : previousOwners) {
            std::cout << "- " << owner << "\n";
        }

        std::cout << "Owner Details:\n";
        for (const auto &detail : ownerDetails) {
            std::cout << detail.first << ": " << detail.second << "\n";
        }
    }

    // 友元声明,允许构建器访问私有成员
    friend class VehicleBuilder;
};

class VehicleBuilder {
private:
    std::unique_ptr<Vehicle> vehicle;

public:
    // 构造函数
    VehicleBuilder(const std::string& make, const std::string& model, int year, double price)
        : vehicle(std::make_unique<Vehicle>(make, model, year, price)) {}

    // 流式设置方法
    VehicleBuilder& setEngineSize(double engineSize) { vehicle->engineSize = engineSize; return *this; }
    VehicleBuilder& setHorsepower(int horsepower) { vehicle->horsepower = horsepower; return *this; }
    VehicleBuilder& setFuelType(const std::string &fuelType) { vehicle->fuelType = fuelType; return *this; }
    VehicleBuilder& setLength(double length) { vehicle->length = length; return *this; }
    VehicleBuilder& setWidth(double width) { vehicle->width = width; return *this; }
    VehicleBuilder& setHeight(double height) { vehicle->height = height; return *this; }
    VehicleBuilder& setCurbWeight(double curbWeight) { vehicle->curbWeight = curbWeight; return *this; }

    VehicleBuilder& addFeature(const std::string &feature) { vehicle->features.push_back(feature); return *this; }
    VehicleBuilder& addSpecification(const std::string &key, const std::string &value) { vehicle->specifications[key] = value; return *this; }
    VehicleBuilder& addSafetyFeature(const std::string &feature) { vehicle->safetyFeatures.insert(feature); return *this; }

    VehicleBuilder& addPreviousOwner(const std::string &owner) { vehicle->previousOwners.push_back(owner); return *this; }
    VehicleBuilder& addOwnerDetail(const std::string &key, const std::string &value) { vehicle->ownerDetails[key] = value; return *this; }

    // 类型转换运算符重载
    operator std::unique_ptr<Vehicle>() { return std::move(vehicle); }
};

int main() {
    std::unique_ptr<Vehicle> car = VehicleBuilder("Toyota", "Camry", 2021, 24000)
        .setEngineSize(2.5)
        .setHorsepower(203)
        .setFuelType("Gasoline")
        .setLength(4.88)
        .setWidth(1.84)
        .setHeight(1.45)
        .setCurbWeight(1495)
        .addFeature("Air Conditioning")
        .addFeature("Navigation System")
        .addSpecification("Transmission", "8-speed automatic")
        .addSpecification("Drivetrain", "FWD")
        .addSafetyFeature("ABS")
        .addSafetyFeature("Airbags")
        .addPreviousOwner("John Doe")
        .addOwnerDetail("Current Owner", "Jane Smith");

    car->printVehicleInfo();

    return 0;
}

3.2 传统构造器

传统构造器是怎么实现的?他的优点是什么?

虽然说上一个流式构造器,已经非常优秀了,但是经典构造器依旧有优点(这点见仁见智)!

方式:要创建新的对象,就写一个具体的类实现抽象类。
优点 :

  • 创建一个具体的类,后下次就不用创建了,直接用就可以,提高复用性 。
  • 我们可以选择不同的类,实现选配的效果

3.2.1 UML类图

经典构造器UML类图

3.2.2实现

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <memory>

// 产品类
class Vehicle {
private:
    // 基本属性
    std::string make;
    std::string model;
    int year;
    double price;

    // 动力属性
    double engineSize;
    int horsepower;
    std::string fuelType;

    // 尺寸和重量
    double length;
    double width;
    double height;
    double curbWeight;

    // 车辆特征
    std::vector<std::string> features;
    std::map<std::string, std::string> specifications;
    std::set<std::string> safetyFeatures;

    // 拥有者信息
    std::list<std::string> previousOwners;
    std::map<std::string, std::string> ownerDetails;

public:
    // 设置各属性的方法
    void setMake(const std::string& make) { this->make = make; }
    void setModel(const std::string& model) { this->model = model; }
    void setYear(int year) { this->year = year; }
    void setPrice(double price) { this->price = price; }
    void setEngineSize(double engineSize) { this->engineSize = engineSize; }
    void setHorsepower(int horsepower) { this->horsepower = horsepower; }
    void setFuelType(const std::string& fuelType) { this->fuelType = fuelType; }
    void setLength(double length) { this->length = length; }
    void setWidth(double width) { this->width = width; }
    void setHeight(double height) { this->height = height; }
    void setCurbWeight(double curbWeight) { this->curbWeight = curbWeight; }
    void addFeature(const std::string& feature) { features.push_back(feature); }
    void addSpecification(const std::string& key, const std::string& value) { specifications[key] = value; }
    void addSafetyFeature(const std::string& feature) { safetyFeatures.insert(feature); }
    void addPreviousOwner(const std::string& owner) { previousOwners.push_back(owner); }
    void addOwnerDetail(const std::string& key, const std::string& value) { ownerDetails[key] = value; }

    // 打印车辆信息的方法
    void printVehicleInfo() const {
        std::cout << "Make: " << make << "\nModel: " << model << "\nYear: " << year << "\nPrice: $" << price << "\n";
        std::cout << "Engine Size: " << engineSize << "L\nHorsepower: " << horsepower << "\nFuel Type: " << fuelType << "\n";
        std::cout << "Dimensions (LxWxH): " << length << " x " << width << " x " << height << " meters\n";
        std::cout << "Curb Weight: " << curbWeight << " kg\n";
        
        std::cout << "Features:\n";
        for (const auto &feature : features) {
            std::cout << "- " << feature << "\n";
        }

        std::cout << "Specifications:\n";
        for (const auto &spec : specifications) {
            std::cout << spec.first << ": " << spec.second << "\n";
        }

        std::cout << "Safety Features:\n";
        for (const auto &safety : safetyFeatures) {
            std::cout << "- " << safety << "\n";
        }

        std::cout << "Previous Owners:\n";
        for (const auto &owner : previousOwners) {
            std::cout << "- " << owner << "\n";
        }

        std::cout << "Owner Details:\n";
        for (const auto &detail : ownerDetails) {
            std::cout << detail.first << ": " << detail.second << "\n";
        }
    }
};

// 抽象建造者
class VehicleBuilder {
public:
    virtual ~VehicleBuilder() = default;

    virtual void setMake() = 0;
    virtual void setModel() = 0;
    virtual void setYear() = 0;
    virtual void setPrice() = 0;
    virtual void setEngineSize() = 0;
    virtual void setHorsepower() = 0;
    virtual void setFuelType() = 0;
    virtual void setDimensions() = 0;
    virtual void setCurbWeight() = 0;
    virtual void addFeatures() = 0;
    virtual void addSpecifications() = 0;
    virtual void addSafetyFeatures() = 0;
    virtual void addPreviousOwners() = 0;
    virtual void addOwnerDetails() = 0;

    virtual std::unique_ptr<Vehicle> getVehicle() = 0;
};

// 具体建造者
class ConcreteVehicleBuilder : public VehicleBuilder {
private:
    std::unique_ptr<Vehicle> vehicle;

public:
    ConcreteVehicleBuilder() {
        vehicle = std::make_unique<Vehicle>();
    }

    void setMake() override {
        vehicle->setMake("Toyota");
    }

    void setModel() override {
        vehicle->setModel("Camry");
    }

    void setYear() override {
        vehicle->setYear(2021);
    }

    void setPrice() override {
        vehicle->setPrice(24000);
    }

    void setEngineSize() override {
        vehicle->setEngineSize(2.5);
    }

    void setHorsepower() override {
        vehicle->setHorsepower(203);
    }

    void setFuelType() override {
        vehicle->setFuelType("Gasoline");
    }

    void setDimensions() override {
        vehicle->setLength(4.88);
        vehicle->setWidth(1.84);
        vehicle->setHeight(1.45);
    }

    void setCurbWeight() override {
        vehicle->setCurbWeight(1495);
    }

    void addFeatures() override {
        vehicle->addFeature("Air Conditioning");
        vehicle->addFeature("Navigation System");
    }

    void addSpecifications() override {
        vehicle->addSpecification("Transmission", "8-speed automatic");
        vehicle->addSpecification("Drivetrain", "FWD");
    }

    void addSafetyFeatures() override {
        vehicle->addSafetyFeature("ABS");
        vehicle->addSafetyFeature("Airbags");
    }

    void addPreviousOwners() override {
        vehicle->addPreviousOwner("John Doe");
    }

    void addOwnerDetails() override {
        vehicle->addOwnerDetail("Current Owner", "Jane Smith");
    }

    std::unique_ptr<Vehicle> getVehicle() override {
        return std::move(vehicle);
    }
};

// 指挥者类
class Director {
private:
    VehicleBuilder* builder;

public:
    void setBuilder(VehicleBuilder* builder) {
        this->builder = builder;
    }

    std::unique_ptr<Vehicle> construct() {
        builder->setMake();
        builder->setModel();
        builder->setYear();
        builder->setPrice();
        builder->setEngineSize();
        builder->setHorsepower();
        builder->setFuelType();
        builder->setDimensions();
        builder->setCurbWeight();
        builder->addFeatures();
        builder->addSpecifications();
        builder->addSafetyFeatures();
        builder->addPreviousOwners();
        builder->addOwnerDetails();
        return builder->getVehicle();
    }
};

// 主函数
int main() {
    Director director;
    ConcreteVehicleBuilder builder;

    director.setBuilder(&builder);
    std::unique_ptr<Vehicle> car = director.construct();

    car->printVehicleInfo();

    return 0;
}

3.3 组合构造器

个人觉得这个依然是巅峰了,当时第一次看到这个实现方式真的是惊为天人!

优点:可以选配(特定一类属性进行初始化,再也不用担心到不到要初始化的类了!)

3.3.1UML类图

组合构造器UML类图

3.3.2实现

#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <memory>
using namespace std;

class Vehicle_Builder;
class V_Basic_Properties_Builder;
class V_Dynamic_Properties_Builder;
class V_Size_And_Weight_Builder;
class V_Vehicle_Features_Builder;
class V_Owner_Information_Builder;

class Vehicle {
private:
    // 基本属性
    std::string make;
    std::string model;
    int year;
    double price;

    // 动力属性
    double engineSize;
    int horsepower;
    std::string fuelType;

    // 尺寸和重量
    double length;
    double width;
    double height;
    double curbWeight;

    // 车辆特征
    std::vector<std::string> features;
    std::map<std::string, std::string> specifications;
    std::set<std::string> safetyFeatures;

    // 拥有者信息
    std::list<std::string> previousOwners;
    std::map<std::string, std::string> ownerDetails;

public:
    static Vehicle_Builder create();
    Vehicle(){}

    // 打印车辆信息的方法
    void printVehicleInfo() const {
        std::cout << "制造商: " << make << "\n型号: " << model << "\n年份: " << year << "\n价格: $" << price << "\n";
        std::cout << "发动机大小: " << engineSize << "L\n马力: " << horsepower << "\n燃料类型: " << fuelType << "\n";
        std::cout << "尺寸 (长x宽x高): " << length << " x " << width << " x " << height << " 米\n";
        std::cout << "整备质量: " << curbWeight << " 千克\n";
        
        std::cout << "特征:\n";
        for (const auto &feature : features) {
            std::cout << "- " << feature << "\n";
        }

        std::cout << "规格:\n";
        for (const auto &spec : specifications) {
            std::cout << spec.first << ": " << spec.second << "\n";
        }

        std::cout << "安全特征:\n";
        for (const auto &safety : safetyFeatures) {
            std::cout << "- " << safety << "\n";
        }

        std::cout << "之前的车主:\n";
        for (const auto &owner : previousOwners) {
            std::cout << "- " << owner << "\n";
        }

        std::cout << "车主详细信息:\n";
        for (const auto &detail : ownerDetails) {
            std::cout << detail.first << ": " << detail.second << "\n";
        }
    }

    // 友元声明,允许构建器访问私有成员
    friend class Vehicle_Builder;
    friend class V_Basic_Properties_Builder;
    friend class V_Dynamic_Properties_Builder;
    friend class V_Size_And_Weight_Builder;
    friend class V_Vehicle_Features_Builder;
    friend class V_Owner_Information_Builder;
};

class Vehicle_Builder_Base {
protected:
    Vehicle& vehicle;
    explicit Vehicle_Builder_Base(Vehicle& vehicle) : vehicle(vehicle) {}

public:
    operator Vehicle() { return std::move(vehicle); }
    V_Basic_Properties_Builder basic_properties() const;
    V_Dynamic_Properties_Builder dynamic_properties() const;
    V_Size_And_Weight_Builder size_and_weight() const;
    V_Vehicle_Features_Builder vehicle_features() const;
    V_Owner_Information_Builder owner_information() const;
};

class Vehicle_Builder : public Vehicle_Builder_Base {
protected:
    Vehicle vehicle;
public:
    Vehicle_Builder() : Vehicle_Builder_Base(vehicle) {}
};

class V_Basic_Properties_Builder : public Vehicle_Builder_Base {
public:
    explicit V_Basic_Properties_Builder(Vehicle& vehicle) : Vehicle_Builder_Base(vehicle) {}

    V_Basic_Properties_Builder& make(const std::string& make) {
        vehicle.make = make;
        return *this;
    }

    V_Basic_Properties_Builder& model(const std::string& model) {
        vehicle.model = model;
        return *this;
    }

    V_Basic_Properties_Builder& year(int year) {
        vehicle.year = year;
        return *this;
    }

    V_Basic_Properties_Builder& price(double price) {
        vehicle.price = price;
        return *this;
    }
};

class V_Dynamic_Properties_Builder : public Vehicle_Builder_Base {
public:
    explicit V_Dynamic_Properties_Builder(Vehicle& vehicle) : Vehicle_Builder_Base(vehicle) {}

    V_Dynamic_Properties_Builder& engineSize(double engineSize) {
        vehicle.engineSize = engineSize;
        return *this;
    }

    V_Dynamic_Properties_Builder& horsepower(int horsepower) {
        vehicle.horsepower = horsepower;
        return *this;
    }

    V_Dynamic_Properties_Builder& fuelType(const std::string& fuelType) {
        vehicle.fuelType = fuelType;
        return *this;
    }
};

class V_Size_And_Weight_Builder : public Vehicle_Builder_Base {
public:
    explicit V_Size_And_Weight_Builder(Vehicle& vehicle) : Vehicle_Builder_Base(vehicle) {}

    V_Size_And_Weight_Builder& length(double length) {
        vehicle.length = length;
        return *this;
    }

    V_Size_And_Weight_Builder& width(double width) {
        vehicle.width = width;
        return *this;
    }

    V_Size_And_Weight_Builder& height(double height) {
        vehicle.height = height;
        return *this;
    }

    V_Size_And_Weight_Builder& curbWeight(double curbWeight) {
        vehicle.curbWeight = curbWeight;
        return *this;
    }
};

class V_Vehicle_Features_Builder : public Vehicle_Builder_Base {
public:
    explicit V_Vehicle_Features_Builder(Vehicle& vehicle) : Vehicle_Builder_Base(vehicle) {}

    V_Vehicle_Features_Builder& addFeature(const std::string& feature) {
        vehicle.features.push_back(feature);
        return *this;
    }

    V_Vehicle_Features_Builder& addSpecification(const std::string& key, const std::string& value) {
        vehicle.specifications[key] = value;
        return *this;
    }

    V_Vehicle_Features_Builder& addSafetyFeature(const std::string& safetyFeature) {
        vehicle.safetyFeatures.insert(safetyFeature);
        return *this;
    }
};

class V_Owner_Information_Builder : public Vehicle_Builder_Base {
public:
    explicit V_Owner_Information_Builder(Vehicle& vehicle) : Vehicle_Builder_Base(vehicle) {}

    V_Owner_Information_Builder& addPreviousOwner(const std::string& owner) {
        vehicle.previousOwners.push_back(owner);
        return *this;
    }

    V_Owner_Information_Builder& addOwnerDetail(const std::string& key, const std::string& value) {
        vehicle.ownerDetails[key] = value;
        return *this;
    }
};

Vehicle_Builder Vehicle::create() {
    return Vehicle_Builder();
}

V_Basic_Properties_Builder Vehicle_Builder_Base::basic_properties() const {
    return V_Basic_Properties_Builder(vehicle);
}

V_Dynamic_Properties_Builder Vehicle_Builder_Base::dynamic_properties() const {
    return V_Dynamic_Properties_Builder(vehicle);
}

V_Size_And_Weight_Builder Vehicle_Builder_Base::size_and_weight() const {
    return V_Size_And_Weight_Builder(vehicle);
}

V_Vehicle_Features_Builder Vehicle_Builder_Base::vehicle_features() const {
    return V_Vehicle_Features_Builder(vehicle);
}

V_Owner_Information_Builder Vehicle_Builder_Base::owner_information() const {
    return V_Owner_Information_Builder(vehicle);
}

int main() {
    Vehicle vehicle = Vehicle::create()
        .basic_properties().make("丰田").model("凯美瑞").year(2020).price(30000.0)
        .dynamic_properties().engineSize(2.5).horsepower(203).fuelType("汽油")
        .size_and_weight().length(4.8).width(1.8).height(1.4).curbWeight(1500)
        .vehicle_features().addFeature("天窗").addSpecification("变速器", "自动").addSafetyFeature("ABS")
        .owner_information().addPreviousOwner("约翰·多伊").addOwnerDetail("当前车主", "简·多伊");

    vehicle.printVehicleInfo();

    return 0;
}

四、总结

对于这三种构造器,我还是喜欢组合和流式,因为个人觉得他是真正做到把对象的创建和对象的使用分离开来的!

对于friend关键字,我平时也是可以用的,不过要更加深思熟虑,破坏封装性也是真的,但也不是不用这个C++存在的特性。

最后!作者也是刚学,写下对此设计模式的疑惑,如有错误,请指正!
点个赞吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736544.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在线随机密码生成工具

对于运维工作&#xff0c;经常需要生产随机密码&#xff0c;这里介绍一款在线生成密码工具&#xff0c;支持配置密码组合类型&#xff0c;如数字、字母大小写、特殊字符等&#xff0c;还能排除某些特殊字符。 在线随机密码生成工具 https://tool.hiofd.com/random-string-gen…

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测 目录 SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【SCI一区级】Matlab实现BO-Transformer-LSTM多变量时间序列预测&#xff0c;贝叶斯…

嵌入式中逻辑分析仪与示波器的基本原理

大家好,今天主要给大家分享一下,嵌入式中如何使用逻辑分析仪和示波器的方法,希望对大家有所帮助。 https://dreamsourcelab.cn/ 第一:什么是逻辑分析仪 是否遇到使用示波器分析数字电路的冏境:深度不够,时间太短,无法抓到想要的波形,没有协议内容解析? 逻辑分析仪…

项目八 OpenStack存储管理

任务一 理解OpenStack块存储服务 1.1 •Cinder的主要功能 • 提供 持久性块存储资源&#xff0c;供 Nova 计算服务的虚拟机实例使用 。 • 为 管理块存储设备提供一套方法&#xff0c;对卷实现从创建到删除的整个生命周期 管理。 • 将 不同的后端存储进行封装&#xff0c;对外…

利用竞争智慧与大型语言模型:假新闻检测的新突破

Explainable Fake News Detection With Large Language Model via Defense Among Competing Wisdom 论文地址: Explainable Fake News Detection with Large Language Model via Defense Among Competing Wisdom | Proceedings of the ACM on Web Conference 2024https://dl.…

uni-CMS:全端开源内容管理系统的技术探索

摘要 本文介绍了uni-CMS&#xff0c;一个基于uniCloud开发的开源内容管理系统&#xff08;CMS&#xff09;。该系统旨在帮助开发者快速搭建并管理内容丰富的网站、小程序和移动应用。通过其全端渲染、内容安全检测、广告解锁付费内容以及AI生成文章等特性&#xff0c;uni-CMS不…

【算法】优先级队列-基础与应用

优先级队列&#xff08;Priority Queue&#xff09;是一种特殊的队列类型&#xff0c;它允许在其元素中分配优先级。与传统的先进先出&#xff08;FIFO&#xff09;队列不同&#xff0c;优先级队列中元素的出队顺序取决于它们的优先级。优先级较高的元素会被优先处理&#xff0…

数组移除元素算法(以JS为例)

题目&#xff1a;LeeCode第27题 答案&#xff1a; 算法思想&#xff1a;双指针 这段代码实际上使用了一种简化版的双指针技术来实现元素的移除。这里的双指针技术并不是传统意义上的两个指针&#xff0c;而是一个索引k作为辅助指针&#xff0c;用来记录新数组&#xff08;或原…

面试:关于word2vec的相关知识点Hierarchical Softmax和NegativeSampling

1、为什么需要Hierarchical Softmax和Negative Sampling 从输入层到隐含层需要一个维度为NK的权重矩阵&#xff0c;从隐含层到输出层又需要一个维度为KN的权重矩阵&#xff0c;学习权重可以用反向传播算法实现&#xff0c;每次迭代时将权重沿梯度更优的方向进行一小步更新。但…

机器学习基础:与Python关系和未来发展

目录 初识Python Python的由来 自由软件运动 编译方式的演进 Python语言的特点 语法简单&#xff0c;易于理解 语法结构清晰&#xff0c;快速上手 丰富的第三方库 机器学习 监督学习 无监督学习 半监督学习 欢迎回到我们的神经网络与深度学习Tensorflow实战学习&am…

Python 虚拟环境 requirements.txt 文件生成 ;pipenv导出pip安装文件

搜索关键词: Python 虚拟环境Pipenv requirements.txt 文件生成;Pipenv 导出 pip requirements.txt安装文件 本文基于python版本 >3.9 文章内容有效日期2023年01月开始(因为此方法从这个时间开始是完全ok的) 上述为pipenv的演示版本 使用以下命令可精准生成requirement…

thrift接口调用工具

写了一个thrift接口调用工具 导入thrift文件就可以直接调用相应接口 工具会根据thrift文件中接口的参数名&#xff0c;参数类型&#xff0c;返回值等等&#xff0c;自动生成接口参数&#xff0c;和结果json化显示。 https://github.com/HuaGouFdog/Fdog-Kit

Java启动jar设置内存分配详解

在微服务架构越来越盛行的情况下&#xff0c;我们通常一个系统都会拆成很多个小的服务&#xff0c;但是最终部署的时候又因为没有那么多服务器只能把多个服务部署在同一台服务器上&#xff0c;这个时候问题就来了&#xff0c;服务器内存不够&#xff0c;这个时候我们就需要对每…

1.3 Sqoop 数据同步工具详细教程

Apache Sqoop 是一个开源工具&#xff0c;用于在 Apache Hadoop 和关系型数据库&#xff08;如 MySQL、Oracle、PostgreSQL 等&#xff09;之间高效传输数据。Sqoop 可以将结构化数据从关系型数据库导入到 Hadoop 的 HDFS、Hive 和 HBase 中&#xff0c;也可以将数据从 Hadoop …

DIVE INTO DEEP LEARNING 50-55

文章目录 50. semantic segmentation50.1 Basic concepts50.2 Major application 51. Transposed convolution51.1 Basic concepts51.2 Major role51.3 Implementation steps and application areas51.4 Transposed convolution51.5 Transposed convolution is a type of convo…

物联网系统运维——移动电商应用发布,Tomcat应用服务器,实验CentOS 7安装JDK与Tomcat,配置Tomcat Web管理界面

一.Tomcat应用服务器 1.Tomcat介绍 Tomcat是- -个免费的开源的Ser Ivet容器&#xff0c;它是Apache基金会的Jakarta 项目中的一个核心项目&#xff0c;由Apache&#xff0c; Sun和其他一 些公司及个人共同开发而成。Tomcat是一一个小型的轻量级应用服务器&#xff0c;在中小型…

从零入手人工智能(5)—— 决策树

1.前言 在上一篇文章《从零入手人工智能&#xff08;4&#xff09;—— 逻辑回归》中讲述了逻辑回归这个分类算法&#xff0c;今天我们的主角是决策树。决策树和逻辑回归这两种算法都属于分类算法&#xff0c;以下是决策树和逻辑回归的相同点&#xff1a; 分类任务&#xff1…

[SAP ABAP] 排序内表数据

语法格式 整表排序 SORT <itab> [ASCENDING|DESCENDING]. 按指定字段排序 SORT <itab> BY f1 [ASCENDING|DESCENDING] f2 [ASCENDING|DESCENDING] ... fn [ASCENDING|DESCENDING].<itab>&#xff1a;代表内表 不指定排序方式则默认升序排序 示例1 结果显…