假设我们有一个生产车的工厂,每辆车有如下属性: 系列、颜色、载人数
头文件如下:
#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