最近在学设计模式,对于建造者模式找了大量的资料,最后看到这篇文章写得比较通俗易懂(建造者模式及C++实现),本文在这篇文章的基础上进行学习。
1 核心
建造者模式适合于产品各个模块内建造过程多变,而各个模块相对的建造顺序稳定的情况。
建造者模式的类图如下:
2 具体实现
2.1 产品product
产品拥有三个参数para,有三个方法分别进行设置set,还有一个展示参数的方法show。
Product.h
#pragma once
class Product
{
public:
Product();
~Product();
//产品拥有分别设置三个参数的三个方法
void setA(int a);
void setB(int b);
void setC(int c);
//展现产品的方法
void show();
private:
//产品拥有三个参数
int paraA;
int paraB;
int paraC;
};
Product.cpp
#include "Product.h"
#include<iostream>
using std::cout;
using std::endl;
Product::Product(){}
Product::~Product(){}
void Product::setA(int a)
{
paraA = a;
}
void Product::setB(int b)
{
paraB = b;
}
void Product::setC(int c)
{
paraC = c;
}
void Product::show()
{
cout << paraA << " " << paraB << " " << paraC << endl;
}
2.2 建造者Builder
建造者基类提供建造产品各个模块的接口,建造者具体子类实现基类接口,建造具体的产品。产品各个模块内建造过程的需求变化,可增加建造者具体子类,以满足模块内建造过程变化的需求。
AbstractBuilder.h
#pragma once
#include"Product.h"
class AbstractBuilder
{
public:
AbstractBuilder();
virtual ~AbstractBuilder();
//产品Product内拥有三个模块,对应提供给具体子类三个建造接口
//设置为纯虚函数,子类必须实现
virtual void buildA(int) = 0;
virtual void buildB(int) = 0;
virtual void buildC(int) = 0;
//给外界提供获取产品的接口
virtual Product* getProduct() = 0;
//创建产品毛坯,需要通过三个模块的建造才能出厂。
virtual void createProduct() = 0;
};
AbstractBuilder.cpp
#include "AbstractBuilder.h"
AbstractBuilder::AbstractBuilder(){}
AbstractBuilder::~AbstractBuilder(){}
ConcreteBuilder.h
#pragma once
#include "AbstractBuilder.h"
class ConcreteBuilder :
public AbstractBuilder
{
public:
ConcreteBuilder();
~ConcreteBuilder();
//实现基类提供的接口
void buildA(int);
void buildB(int);
void buildC(int);
Product* getProduct();
void createProduct();
private:
//建造对象
Product* curProduct;
};
ConcreteBuilder.cpp
#include "ConcreteBuilder.h"
ConcreteBuilder::ConcreteBuilder(){}
ConcreteBuilder::~ConcreteBuilder(){}
void ConcreteBuilder::createProduct()
{
curProduct = new Product();
}
void ConcreteBuilder::buildA(int a)
{
curProduct->setA(a);
}
void ConcreteBuilder::buildB(int b)
{
curProduct->setB(b);
}
void ConcreteBuilder::buildC(int c)
{
curProduct->setC(c);
}
Product* ConcreteBuilder::getProduct()
{
return curProduct;
}
2.3 导演Director
虽然Builder提供了对Product各个模块的建造方法,但是各个模块的建造顺序却没有定下来,而这个建造顺序是相对稳定的,也就是不需要修改的,因此独立出一个Director类来确定建造顺序,同时将这个稳定的建造顺序方法提供给客户即可。
对于客户来说,我想要使用某一种建造方法ConcreteBuilder做出我的产品Product,导演Director你给我造出来,我只需要从你这里得到产品Product即可。
Director.h
#pragma once
#include"AbstractBuilder.h"
class Director
{
public:
//客户需要告知导演使用哪一种建造方法
Director(AbstractBuilder* builder);
~Director();
//客户需要告知建造过程/产品的核心参数
void construct(int a, int b, int c);
//提供客户产品,客户也可以直接使用Builder获取该产品(这是我自己加上的方法)
Product* getProduct();
private:
//导演需要知道自己在导演哪一种建造过程
AbstractBuilder *curBuilder;
};
2.4 客户端使用Main
可以开始使用建造者模式建造我们的产品了。
#pragma once
#include"Director.h"
#include"ConcreteBuilder.h"//必须包含,否则无从找到具体建造者类
#include<iostream>
using std::cout;
using std::endl;
int main()
{
//需要告知Director使用哪一种具体的建造方法
AbstractBuilder* builder = new ConcreteBuilder();
Director* director = new Director(builder);
//需要告知Director建造的参数
director->construct(5, 2, 33);
//可以从Director获取产品
Product*product1 = director->getProduct();
product1->show();
//也可以直接从建造者手上获取产品
Product*product2 = builder->getProduct();
product2->show();
system("pause");
return 0;
}
运行结果:
2.5 需求改变
客户说:现在需求变了,你这个系统需要对我给的参数做进一步处理才能加到产品上,我要它们的平方作为产品参数,而不是直接设置成产品参数。
开发者说:好,马上给你修改。
开发者想:我只需要添加一个具体的建造子类即可满足你的需求。
ConcreteBuilder1.h
#pragma once
#include "AbstractBuilder.h"
class ConcreteBuilder1 :
public AbstractBuilder
{
public:
ConcreteBuilder1();
~ConcreteBuilder1();
void buildA(int);
void buildB(int);
void buildC(int);
Product* getProduct();
void createProduct();
private:
Product* curProduct;
};
ConcreteBuilder1.cpp
#include "ConcreteBuilder1.h"
ConcreteBuilder1::ConcreteBuilder1(){}
ConcreteBuilder1::~ConcreteBuilder1(){}
void ConcreteBuilder1::buildA(int a)
{
curProduct->setA(a*a);
}
void ConcreteBuilder1::buildB(int b)
{
curProduct->setB(b*b);
}
void ConcreteBuilder1::buildC(int c)
{
curProduct->setC(c*c);
}
Product* ConcreteBuilder1::getProduct()
{
return curProduct;
}
void ConcreteBuilder1::createProduct()
{
curProduct = new Product();
}
客户端Main.h
#pragma once
#include"Director.h"
#include"ConcreteBuilder1.h"
#include<iostream>
using std::cout;
using std::endl;
int main()
{
AbstractBuilder* builder = new ConcreteBuilder1();
Director* director = new Director(builder);
director->construct(5, 2, 33);
Product*product1 = director->getProduct();
product1->show();
Product*product2 = builder->getProduct();
product2->show();
system("pause");
return 0;
}
运行结果:
客户想:这个开发者不错啊,对我需求的响应真快。
开发者想:小case啦,因为我使用了建造者模式。
3 讨论
如果不使用建造者模式,对上述需求需求改动Product类的set方法,违反了OO设计原则:对修改封闭,对扩展开放原则。