C++使用内部类实现一种Builder模式(属性内容不对外暴露, 不需管理指针)

假设我们有一个生产车的工厂,每辆车有如下属性: 系列、颜色、载人数

头文件如下:

#ifndef TEST_H
#define TEST_H

#include <string>
#include <memory>

using namespace std;

class Car
{
public:
    class Builder
    {
    public:
        Builder(const Builder &builderArg);
        Builder(const Builder &&builderArg);
        Builder& operator=(const Builder &builderArg);
        Builder& operator=(const Builder &&builderArg);
           
        Builder(const string &series);

        Builder& setColor(const string &color);    
        Builder& setSize(const int size);                    
        
        Car build();

    private:
        shared_ptr<void> carBuildData;
        friend class Car;
    };
    
    void drive();

    Car() = default;
    ~Car() = default;
    Car(const Builder &builder);
    Car(const Car &carArg);
    Car(const Car &&carArg);
    Car& operator=(const Car &carArg);
    Car& operator=(const Car &&carArg);

private:
    shared_ptr<void> carData;
};

#endif // !TEST_H

shared_ptr<void>的目的在于希望内部数据隐藏,对外不体现。

实现如下:

#include "test.h"
#include <iostream>
#include <functional>

struct CarData_t{
    string series;          //  系列
    string color = "RED";   //  颜色
    int size = 5;           //  大小(载人数)

    CarData_t(const string &seriesArg) : series(seriesArg) {}
};

Car::Builder::Builder(const Car::Builder &builderArg)
{
    carBuildData = builderArg.carBuildData;
}

Car::Builder::Builder(const Car::Builder &&builderArg)
{
    carBuildData = builderArg.carBuildData;
}

Car::Builder& Car::Builder::operator=(const Car::Builder &builderArg)
{
    carBuildData = builderArg.carBuildData;

    return *this;
}

Car::Builder& Car::Builder::operator=(const Car::Builder &&builderArg)
{
    carBuildData = builderArg.carBuildData;

    return *this;
}

Car::Car(const Car &carArg)
{
    carData = carArg.carData;
}

Car::Car(const Car &&carArg)
{
    carData = carArg.carData;
}

Car& Car::operator=(const Car &carArg)
{
    carData = carArg.carData;

    return *this;
}

Car& Car::operator=(const Car &&carArg)
{
    carData = carArg.carData;

    return *this;
}

Car::Builder::Builder(const string &series)
{
    CarData_t testdata(series);

    carBuildData = make_shared<CarData_t>(testdata);
}

Car Car::Builder::build()
{
    Car test(*this);

    // 这里直接返回, 函数返回值Car未加&,会触发移动构造函数,如果返回值为Car&,会触发拷贝构造函数
    return test;
}

//  减少重复造轮子,每个set函数都要判断指针是否为空,用回调可以避免重复判断
void operateTestDataArg(void* testDataVoidPtr, function<void(CarData_t*)> callback)
{
    if (testDataVoidPtr == nullptr) { 
        return; 
    }

    auto testDataPtr = reinterpret_cast<CarData_t*>(testDataVoidPtr);

    if (testDataPtr == nullptr) {
        return;
    }

    callback(testDataPtr);
}

void Car::drive()
{
    operateTestDataArg(carData.get(), [&](CarData_t* testDataPtr) {
        cout << "series : " << testDataPtr->series << "    ";
        cout << "color : " << testDataPtr->color << "    ";
        cout << "size : " << testDataPtr->size << endl;
    });
}

Car::Car(const Builder &builder)
{
    operateTestDataArg(builder.carBuildData.get(), [&](CarData_t* buildDataPtr) {
        carData = make_shared<CarData_t>(*buildDataPtr);
    });
}

Car::Builder& Car::Builder::setColor(const string &color)
{
    operateTestDataArg(carBuildData.get(), [&](CarData_t* buildDataPtr) {
        buildDataPtr->color = color;
    });

    return *this;
}

Car::Builder& Car::Builder::setSize(const int size)
{
    operateTestDataArg(carBuildData.get(), [&](CarData_t* buildDataPtr) {
        buildDataPtr->size = size;
    });

    return *this;
}

下面来使用:

int main()
{
    auto benz = Car::Builder("Benz").build();
    cout << "1 : Benz              "; benz.drive();

	//  设置benz为公司用车,由于实现了赋值运算符函数,使用了shared_ptr, benz析构后CompanyCar也能继续使用,CompanyCar和benz中的carData指向同一片空间,对于shared_ptr来说,指向该空间的指针均析构了后该空间才会自动释放
    auto CompanyCar = benz;
    cout << "2 : CompanyCar        "; 
    CompanyCar.drive();

    auto HondaBaseBuilder = Car::Builder("Honda");

    Car HondaDefault(HondaBaseBuilder);
    cout << "3 : HondaDefault      "; 
    HondaDefault.drive();

    auto HondaBlue = HondaBaseBuilder
        .setColor("Blue")
        .setSize(5)
        .build();

    cout << "4 : HondaBlue         "; 
    HondaBlue.drive();

    auto HondaSmallBlack = HondaBaseBuilder
        .setColor("Black")
        .setSize(2)
        .build();

    cout << "5 : HondaSmallBlack   "; 
    HondaSmallBlack.drive();

    //  ps:HondaBaseBuilder属性一直在变 此时初始化car已经不是默认值了,可以自己加入reset函数扩展 或者重新设置属性,此处功能为保证为Honda系列,不用重复Builder("Honda")
    Car HondaCurrent(HondaBaseBuilder);
    cout << "5 : HondaCurrent      "; 
    HondaCurrent.drive();

    return 0;
}

运行结果:

1 : Benz              series : Benz     color : RED    size : 5
2 : CompanyCar        series : Benz     color : RED    size : 5
3 : HondaDefault      series : Honda    color : RED    size : 5
4 : HondaBlue         series : Honda    color : Blue   size : 5
5 : HondaSmallBlack   series : Honda    color : Black  size : 2
5 : HondaCurrent      series : Honda    color : Black  size : 2
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值