生成者模式

生产器模式

应用场景:

  • 假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便; 因此, 你需要重载这个构造函数, 新建几个只有较少参数的简化版。 但这些构造函数仍需调用主构造函数, 传递一些默认数值来替代省略掉的参数。生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。
  • 当你希望使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用生成器模式。如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤, 具体生成器将实现这些步骤来制造特定形式的产品。 同时, 主管类将负责管理制造步骤的顺序。
  • 使用生成器构造组合树或其他复杂对象。

使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。

问题:

假设有这样一个复杂对象, 在对其进行构造时需要对诸多成员变量和嵌套对象进行繁复的初始化工作。 这些初始化代码通常深藏于一个包含众多参数且让人基本看不懂的构造函数中;

例如, 我们来思考如何创建一个 房屋House对象。 建造一栋简单的房屋, 首先你需要建造四面墙和地板, 安装房门和一套窗户, 然后再建造一个屋顶。 但是如果你想要一栋更宽敞更明亮的房屋, 还要有院子和其他设施 (例如暖气、 排水和供电设备), 那又该怎么办呢?

最简单的方法是扩展房屋基类, 然后创建一系列涵盖所有参数组合的子类。 但最终你将面对相当数量的子类。 任何新增的参数 (例如门廊类型) 都会让这个层次结构更加复杂。

另一种方法则无需生成子类。 你可以在 房屋基类中创建一个包括所有可能参数的超级构造函数, 并用它来控制房屋对象。 这种方法确实可以避免生成子类, 但它却会造成另外一个问题。通常情况下, 绝大部分的参数都没有使用, 这使得对于构造函数的调用十分不简洁。 例如, 只有很少的房子有游泳池, 因此与游泳池相关的参数十之八九是毫无用处的。

解决方案

生成器模式建议将对象构造代码从产品类中抽取出来, 并将其放在一个名为生成器的独立对象中。该模式会将对象构造过程划分为一组步骤, 比如 build­Walls创建墙壁和 build­Door创建房门创建房门等。 每次创建对象时, 你都需要通过生成器对象执行一系列步骤。 重点在于你无需调用所有步骤, 而只需调用创建特定对象配置所需的那些步骤即可。当你需要创建不同形式的产品时, 其中的一些构造步骤可能需要不同的实现。 例如, 木屋的房门可能需要使用木头制造, 而城堡的房门则必须使用石头制造。在这种情况下, 你可以创建多个不同的生成器, 用不同方式实现一组相同的创建步骤。 然后你就可以在创建过程中使用这些生成器 (例如按顺序调用多个构造步骤) 来生成不同类型的对象。

结构

alt text

参考代码

class Car
{
public:
	Car() {}
	int num_seats;
	int engine_model;
	int gps_model;
};
class Manual //汽车使用手册说明
{
public:

};

class Builder
{
public:
	virtual ~Builder() {}
	virtual void reset() = 0;
	virtual void setSeats(int) = 0;
	virtual void setEngine(int) = 0;
	virtual void buildGPS(int) = 0;
};

class CarBuilder :public Builder
{
public:
	CarBuilder() {};

	void reset() { this->car = new Car; }
	void setSeats(int n) { car->num_seats = n; };
	void setEngine(int mode) { car->engine_model = mode; };
	void buildGPS(int g) { car->gps_model = g; };

	Car * getProduct() {
		return car;
	};
private:
	Car*		car;
};

class CarManulaBuilder :public Builder
{
public:
	CarManulaBuilder() {};
	void reset() { this->manulal = new Manual; }
	void setSeats(int n) {
		cout << "this car have " << n << "seats" << std::endl; //使用手册说明
	};
	void setEngine(int mode) {
		cout << "this car engine mode is " << mode << std::endl; //使用手册说明
	};
	void buildGPS(int h) {
		cout << "this car has the GPS and the mode is" << h << std::endl;
	};

	Manual * getProduct() { return manulal; }
private:
	Manual* manulal;
};

class Director
{
public:
	void setBuilder(Builder *b) { builder = b; }
	void constructSportsCar()
	{
		builder->reset();
		builder->setSeats(2);
		builder->setEngine(3); //3 is sport car engine model
		builder->buildGPS(4);
	}
	void constructSUV()
	{
		builder->reset();
		builder->setSeats(4);
		builder->setEngine(5); //5 is sport car engine model
		//builder->buildGPS(4); //SUV没有GPS 不用生成GPS
	}
private:
	Builder * builder;
};

void ClientCode(Director* director)
{
	CarBuilder * carBuilder = new CarBuilder;
	director->setBuilder(carBuilder);
	director->constructSportsCar();
	Car * sportCar = carBuilder->getProduct();
	director->constructSUV();
	Car * suv = carBuilder->getProduct();

	CarManulaBuilder * manulaBuilder = new CarManulaBuilder;
	director->setBuilder(manulaBuilder);
	director->constructSportsCar();
	Manual * sportCarManual = manulaBuilder->getProduct();
	director->constructSUV();
	Manual * suvManual = manulaBuilder->getProduct();

	delete carBuilder;
	delete sportCar;
	delete suv;

	delete manulaBuilder;
	delete sportCarManual;
	delete suvManual;
}

posted on 2021-05-17 16:35  Ultraman_X  阅读(62)  评论(0编辑  收藏  举报

导航