建造者模式
1. Builder Pattern
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
建造者模式的目的很简单就是将一个复杂的对象的创建与其表示想分离。解决的问题就是那种组件基本固定不变而组合变化的过程,这里区别下“抽象工厂”模式,抽象工厂
也是创建一个复杂的对象,而对象内部的组件都是一个系列的,但是组合基本不变。更加关心组件的顺序。
1.1 动机
一个“复杂”的对象的创建的方法,通常组件的各个子部分由一定算法构成;由于需求的变化,复杂对象的各个子部分面临剧烈的变化,而组合他们的方法却是固定的。
利用“封装隔离”的方法,将子部分隔离开,保证稳定的构建方法,不会随着需求的变化而变化。
优点和缺点等我们后面再谈。
2. 场景复现
这是菜鸟教程上的 建造者模式的结构图,我就是来用C++复现这个结构图
#include <iostream>
#include <string>
#include <list>
#include <memory>
class Packing {
public:
virtual std::string pack() {}
}; // class Packing
class Item {
public:
virtual std::string name() {}
virtual float price() {}
virtual ~Item() {
if (pack_) {
delete pack_;
pack_ = nullptr;
}
}
public:
Packing* pack_ = nullptr;
}; // class Item
class Wrapper : public Packing {
public:
virtual std::string pack() override { return "Wrapper"; }
}; // class Wrapper
class Bottle : public Packing {
public:
virtual std::string pack() override { return "Bottle";}
}; // class Bottle
class Burger : public Item {
public:
virtual float price() = 0;
Burger() {
Item::pack_ = new Wrapper();
}
~Burger() {
if(Item::pack_) {
delete Item::pack_;
Item::pack_ = nullptr;
}
}
}; // class Burger
class ColdDrink : public Item {
public:
virtual float price() = 0;
ColdDrink() {
Item::pack_ = new Bottle();
}
~ColdDrink() {
if(Item::pack_) {
delete Item::pack_;
Item::pack_ = nullptr;
}
}
}; // class ColdDrink
class VegBurger : public Burger {
public:
virtual float price() override { return 25.0f; }
virtual std::string name() override { return "VegBurger"; }
}; // class VegBurger
class ChickenBurger : public Burger {
public:
virtual float price() override { return 50.0f; }
virtual std::string name() override { return "ChickenBurger"; }
}; // class ChickenBurger
class Coke : public ColdDrink {
public:
virtual float price() override { return 15.0f; }
virtual std::string name() override { return "Coke"; }
}; // class Coke
class Pepsi : public ColdDrink {
public:
virtual float price() override { return 10.0f; }
virtual std::string name() override { return "Pepsi"; }
}; // class Pepsi
class Meal {
private:
std::list<Item*> items;
public:
Meal() { items.clear(); }
void addItem(Item* item) { items.push_back(item); }
float getCost(){
float cost = 0.0f;
for(auto& it : items) {
cost += it->price();
}
return cost;
}
void showItems() {
for (auto& it : items) {
std::cout << " Item :"<< it->name() << " , ";
std::cout << " Packing :"<< it->pack_->pack() << " , ";
std::cout << " Price :"<< it->price() << std::endl;
}
}
~Meal() {
for (auto& it : items) {
if (it) {
delete it;
it = nullptr;
}
}
items.clear();
}
};
class MealBuilder {
public:
Meal* prepareMeal(const std::string& burger, const std::string& drink ) {
Meal* meal = new Meal();
if (burger == "VegBurger") {
meal->addItem(new VegBurger()) ;
} else {
meal->addItem(new ChickenBurger());
}
if (drink == "Coke") {
meal->addItem(new Coke());
} else {
meal->addItem(new Pepsi());
}
return meal;
}
};
int main(int argc, char** argv) {
std::unique_ptr<MealBuilder> m_builder(new MealBuilder);
std::unique_ptr<Meal> meal1(m_builder->prepareMeal("VegBurger", "Coke"));
meal1->showItems();
std::cout << "prices:" << meal1->getCost() << std::endl;
std::unique_ptr<Meal> meal2(m_builder->prepareMeal("", ""));
meal2->showItems();
std::cout << "prices:" << meal2->getCost() << std::endl;
return 0;
}
编译
g++ -o tt testBuilder.cpp -std=c++11
运行
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./tt
运行结果
定义
代码改进版
将一个复杂对象的构建与其表示相分离,使得相同的构建的方式可以创建不同的表示。
建造者模式主要是解决复杂对象的创建,我们可以把对象的数据成员和基本的方法单独生成一个类, 然后类的创建过程单独抽成一个类,而创建类过程中具体不变的
过程也可以单独抽成一个类,变化的部分继续抽象。
举个例子
比如建造房子我们可以有个基类叫class House,其他的具体的房子可以继承这个类。
然后是造房子的过程我们可以叫做class HouseBuilder, 然后House builder中变化的部分,比如使用什么样的颜色,砖等,这些可以和房子具体的
创建过程隔离开。比如房子的创建过程是先地基然后墙窗户,这些是不变的,可以新成一个类 class HouseDirector。这个基本不变。
而剩余的House Builder可以抽象成一个基类class BaseHouseBuilder, 具体的可以继承这个类重写。
下面这段代码我结合单例,反射机制,工厂模式以及这里的builder模式,写了一个可以动态改变
菜单的代码,其中由于是做示范,还有由于上段的是java代码改编的,命名之类的没做好规范。类之类的也没分文件,只要能看懂什么意思就好了。
代码思路:
1、Item的创建,使用工厂模式,以及多态的一些和菜鸟上。
2、将Item的的创建方法(工厂方法)使用map存起来,这里使用函数指针。为了这个目的工厂方法设成了static
3、builder模式,根据输入的菜单,结合map创建所需要的meal.
注意这里还涉及到不定长参数的处理。
#include <cstdarg>
#include <functional>
#include <iostream>
#include <list>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
class Packing {
public:
virtual std::string pack() { return ""; }
}; // class Packing
class Item {
public:
virtual std::string name() { return ""; }
virtual float price() { return 0.0f; }
virtual ~Item();
public:
Packing* pack_ = nullptr;
}; // class Item
Item::~Item() {
if (pack_) {
delete pack_;
pack_ = nullptr;
}
}
class Wrapper : public Packing {
public:
virtual std::string pack() override { return "Wrapper"; }
}; // class Wrapper
class Bottle : public Packing {
public:
virtual std::string pack() override { return "Bottle"; }
}; // class Bottle
class Burger : public Item {
public:
virtual float price() = 0;
Burger() { Item::pack_ = new Wrapper(); }
virtual ~Burger();
}; // class Burger
Burger::~Burger() {
if (Item::pack_) {
delete Item::pack_;
Item::pack_ = nullptr;
}
}
class ColdDrink : public Item {
public:
virtual float price() = 0;
ColdDrink() { Item::pack_ = new Bottle(); }
virtual ~ColdDrink();
}; // class ColdDrink
ColdDrink::~ColdDrink() {
if (Item::pack_) {
delete Item::pack_;
Item::pack_ = nullptr;
}
}
class VegBurger : public Burger {
public:
virtual float price() override { return 25.0f; }
virtual std::string name() override { return "VegBurger"; }
}; // class VegBurger
class ChickenBurger : public Burger {
public:
virtual float price() override { return 50.0f; }
virtual std::string name() override { return "ChickenBurger"; }
}; // class ChickenBurger
class Coke : public ColdDrink {
public:
virtual float price() override { return 15.0f; }
virtual std::string name() override { return "Coke"; }
}; // class Coke
class Pepsi : public ColdDrink {
public:
virtual float price() override { return 10.0f; }
virtual std::string name() override { return "Pepsi"; }
}; // class Pepsi
class Meal {
public:
std::list<Item*> items;
public:
void showItems();
bool AddItems(Item* item) {
items.push_back(item);
return false;
}
float CalTotalPrice();
~Meal();
};
void Meal::showItems() {
for (auto& it : items) {
std::cout << " Item :" << it->name() << " , ";
std::cout << " Packing :" << it->pack_->pack() << " , ";
std::cout << " Price :" << it->price() << std::endl;
}
}
float Meal::CalTotalPrice() {
float p = 0.0f;
for (auto& it : items) {
p += it->price();
}
return p;
}
Meal::~Meal() {
for (auto& it : items) {
if (it) {
delete it;
it = nullptr;
}
}
items.clear();
}
class MealBuilder {
public:
Meal* meal_ = nullptr;
std::vector<std::string> item_vec_;
public:
MealBuilder() {
meal_ = new Meal();
item_vec_.clear(); };
Meal* GetMeal() { return meal_; };
virtual ~MealBuilder();
void DealParam(int n, ...);
};
MealBuilder::~MealBuilder() { item_vec_.clear(); }
void MealBuilder::DealParam(int n, ...) {
char* str;
va_list vl;
int count = n;
va_start(vl, n);
for (size_t i = 0; i < n; i++) {
str = va_arg(vl, char*);
item_vec_.push_back(str);
}
va_end(vl);
}
class MainFactory {
public:
static MainFactory* Instance() {
if (factory_ == nullptr) {
MainFactory::factory_ = new MainFactory();
}
return factory_;
}
~MainFactory() {
if (factory_) {
delete factory_;
factory_ = nullptr;
}
func_map_.clear();
}
void Register(const std::string& func_name, std::function<Item* ()> func) {
func_map_.insert(std::make_pair(func_name, func));
}
private:
MainFactory() { func_map_.clear(); }
public:
static MainFactory* factory_;
std::unordered_map<std::string, std::function<Item* ()>> func_map_;
};
MainFactory* MainFactory::factory_ = MainFactory::Instance();
class VegBurgerFactory {
public:
static Item* CreateNewItem() { return new VegBurger(); }
};
class ChickenBurgerFactory {
public:
static Item* CreateNewItem() { return new ChickenBurger(); }
};
class CokeFactory {
public:
static Item* CreateNewItem() { return new Coke(); }
};
class PepsiFactory {
public:
static Item* CreateNewItem() { return new Pepsi(); }
};
class MealDirector {
public:
MealBuilder* m_builder_ = nullptr;
public:
MealDirector(MealBuilder* m_builder){
this->m_builder_ = m_builder;
}
void PrepareMeal();
private:
bool AddItem(Item*);
};
bool MealDirector::AddItem(Item* item) {
if (m_builder_) {
return m_builder_->meal_->AddItems(item);
}
return false;
}
void MealDirector::PrepareMeal() {
MainFactory* m_instance = MainFactory::Instance();
for (const auto& it : m_builder_->item_vec_) {
auto func = m_instance->func_map_.find(it);
if (func == m_instance->func_map_.end()) {
std::cout << " not register this function " << std::endl;
return;
}
auto fun = func->second;
Item* item = fun();
AddItem(item);
}
}
class ItemRegister {
public:
void Register();
};
void ItemRegister::Register() {
MainFactory* m_instance = MainFactory::Instance();
m_instance->Register("VegBurger", VegBurgerFactory::CreateNewItem);
m_instance->Register("ChickenBurger", ChickenBurgerFactory::CreateNewItem);
m_instance->Register("Coke", CokeFactory::CreateNewItem);
m_instance->Register("Pepsi", PepsiFactory::CreateNewItem);
}
int main() {
ItemRegister item_register;
item_register.Register();
std::shared_ptr<MealBuilder> m_builder1(new MealBuilder());
m_builder1->DealParam(3, "VegBurger", "Coke", "Pepsi");
std::shared_ptr<MealDirector> meal_director(new MealDirector(m_builder1.get()));
meal_director->PrepareMeal();
std::shared_ptr<Meal> meal1(m_builder1->GetMeal());
meal1->showItems();
std::cout << "prices:" << meal1->CalTotalPrice() << std::endl;
return 0;
}