引言
本篇文章会通过代码和文字的配合来帮助理解建造者模式
简介
建造者模式解决的问题主要是怎么创建一个产品,比如说一个计算机,里面有很多的零部件,我们应该要怎么组装这些零部件变成一个计算机,这个就是建造者模式解决的问题。我们经常和工厂模式相互利用,因为工厂模式解决的问题是创建一个什么对象,而怎么创建的内部细节是由建造者模式解决。
为什么需要这个建造者模式呢?如果没有这个模式,我们工厂里面new出一个对象之后,就用set一个一个的设置属性,但是一旦业务需求发生变动,那就必须要在千万行代码里面找到那个对应的属性然后进行修改,这不符合开闭原则。而我们的建造者干的事情就是把装那些材料交给具体的建造者,按照什么顺序装交给指导员。
建造者模式并不是没有缺点,如果产品之间差距比较大,没有什么共同的特点,那么我们可能就需要非常非常多的建造者,换句话来说我们可以把很多个种类的产品大致总结成一个大类,最后返回的也是这一个大类。
代码

这个是Human的总类,里面交代了一个人类的特性,而我们如果要创建一个人,那么就需要对这些特性进行组装。
cpp
#pragma once
#ifndef _HUMAN_H_
#define _HUMAN_H_
#include "../../Macros.h" // 宏定义
#include <string>
#include <iostream>
namespace bp {
class Human {
CC_SYNTHESIZE(std::string, type, Type);
CC_SYNTHESIZE(std::string, region, Region);
public:
void printInfo() {
std::cout << "type: " << type << std::endl;
std::cout << "region: " << region << std::endl;
}
};
}
#endif
紧接着我们需要设置一个建造者的基类,这个建造者有两个事情,一个是提供设置特性的一个模板函数,方便子类重写,一个是这个建造者的保护类里有Human类型变量,这个是方便子类的不同建造者对human进行组装,然后针对这个变量,设置build()函数,并返回对应的指针(也就是构造完成之后的human)。注意:一个建造者对应一个human
cpp
#pragma once
#ifndef _HUMANBUILDER_H_
#define _HUMANBUILDER_H_
#include "../../../Macros.h" // 宏定义
#include "../Human.h"
#include <string>
namespace bp {
class HumanBuilder {
protected:
Human human;
public:
virtual HumanBuilder* buildType() = 0;
virtual HumanBuilder* buildRegion() = 0;
Human* build();
};
}
#endif
cpp
#include "HumanBuilder.h"
bp::Human* bp::HumanBuilder::build()
{
return new Human(human);
}
这个是其中一个的human的建造,其功能就是对一个human的特性进行设置。
cpp
#pragma once
#ifndef _WHITEMANBUILDER_H_
#define _WHITEMANBUILDER_H_
#include "HumanBuilder.h"
#include "../../../util/ClassHelper.h"
namespace bp {
class WhiteManBuilder : public HumanBuilder {
DECLARE_CLASS(WhiteManBuilder);
public:
WhiteManBuilder* buildType() override;
WhiteManBuilder* buildRegion() override;
};
}
#endif
cpp
#include "WhiteManBuilder.h"
IMPLEMENT_CLASS(bp::WhiteManBuilder);
bp::WhiteManBuilder* bp::WhiteManBuilder::buildType()
{
human.setRegion("白种人");
return this;
}
bp::WhiteManBuilder* bp::WhiteManBuilder::buildRegion()
{
human.setRegion("美洲人");
return this;
}
最后就是指挥官,当我们创建一个指挥官之后,我们会给这个指挥官设置对应的一个建造者(可能是多个),然后我们会通过这个建造者来设置一个human的特性,然后对外面提供一个接口build(),返回的就是human指针,在这个build函数里面我们会根据传入的建造者来建造human
cpp
#pragma once
#ifndef _HUMANDIRECTOR_H_
#define _HUMANDIRECTOR_H_
#include "builder/HumanBuilder.h"
namespace bp {
class HumanDirector {
CC_SYNTHESIZE(HumanBuilder*, m_Builder, Builder);
public:
Human* build();
};
}
#endif
cpp
#include "HumanDirector.h"
bp::Human* bp::HumanDirector::build()
{
return m_Builder
->buildType()
->buildRegion()
->build();
}
最后就是我们的客户端了,首先我们先读配置文件(尽可能不改代码),然后拿到对应的建造者,随后我们创建一个指导员,把这个建造者给到指导员,那么这个指导员就可以调用build(),在这个函数里面就是调用传进来的建造者工作,最后返回human,然后这么一个human就构建完成了。
cpp
#include "../../util/Properties.h"
#include "builder/HumanBuilder.h"
#include "../../util/ClassHelper.h"
#include "HumanDirector.h"
#include <vld.h>
using namespace bp;
int main() {
CREATE_PROPERTIES(prop, conf);
std::string cname = prop.getProperty("bp");
GET_INSTANCE_BY_NAME(HumanBuilder*, builder, cname);
HumanDirector director;
director.setBuilder(builder);
auto human = director.build();
human->printInfo();
delete builder;
delete human;
return 0;
}
总结
本篇文章就到这里结束了!!!希望可以帮助大家理解~~~