一、什么是工厂模式
将一个复杂的对象的构建和其部件分离,将耦合度降到最低。换句话说,就是当初始化一个对象需要很多步骤、复杂工作时,不要使用new来创建对象,而是通过工厂模式抽象出来专门生成对象的一种方法。代码量会增加,但耦合度降低、维护方便。
二、代码结构实现工厂模式
工厂模式设计思路:工厂类负责对产品类的创建,即产品类不能直接实例,不能new,产品类的对象必须由工厂类创建。基于这个原则,产品类可抽象出来,可实现几个子类,针对不同情况,工厂类分别可以创建不同的产品实例(多种产品子类),这些子类,外部同样不能直接new出来,必须由工厂类创建。
2.1、产品类的代码结构
class Product
{
public:
virtual~Product()=0;
virtual void someFunction()=0;
protected:
Product();
private:
};
class ConcreteProduct :public Product
{
public:
~ConcreteProduct();
void someFunction()
{
//具体实现某些功能
};
private:
ConcreteProduct();
};
Product为抽象产品,具有某些共同属性的方法,具体实现过程,让子类实现。由于产品类不可直接new创建,所以需要将构造函数私有化,外部不可访问。(那么工厂类如何可以访问呢?稍后讲解)
2.2、工厂类的代码结构
class Product;
class ConcreteProduct;
class Factory
{
public:
// 用于创建产品类
Product* CreateProduct()
{
Product*product=new ConcreteProduct;
return product;
}
};
Factory为工厂类,用于创建具体产品类对象,如 Product*product=new ConcreteProduct;但是,此时的工厂类是无法访问到子产品类的构造函数的(已经保护起来了),那么此时需要一个友元操作,让子产品类的所有私有的属性、方法,都能够让工厂类访问,此时就需要在子产品类添加友元:friend class Factory;
即最后子产品类,长这样的
class ConcreteProduct :public Product
{
public:
~ConcreteProduct();
void someFunction()
{
//具体实现某些功能
};
friend class Factory;
private:
ConcreteProduct();
};
工厂模式的代码结构就完成了
三、代码实现的注意事项
在编写工厂方法有几个需要注意的地方:
1、抽象产品和子产品类都需要私有化构造函数,否则外部能new出来,工厂模式就失效
2、子产品类需要添加工厂的友元声明,否则工厂类无法访问构造函数,就无法创建对象
3、工厂类需要一个创建产品类的方法,创造子产品类(因为抽象产品为抽象类,此时通过子类对象传递指针,当具体使用这个指针时,实质是子类的指针,执行子类的函数)
4、这点最容易忽略:抽象产品类的析构函数必须为纯虚函数,子类释放时,根据这个纯虚函数指针释放内存,否则会造成内存泄漏,具体关于纯虚函数指针方面以后在讨论。
四、工厂模式的使用方法
现在可以使用工厂来创建产品子类了
Factory factory;
Product* p=factory.CreateProduct();// 注意此时返回的是子类的指针
p->someFunction();// 调用的是子产品类的someFunction成员函数,这个过程就是动态绑定的过程,也是c++的继承与多态特性
在使用过程中可以发现,子产品类并不能new创建,只能通过工厂类创建,这就是工厂模式的核心。
在实际运用过程中会经常遇到这样的方式,此处简单用一个例子演示:
一个汽车公司可以生产三款汽车,如奥迪、宝马、日产,这些汽车各自有自身的功能如不同的速度,还有其他各方面的细节,省略。简单的把这个工厂模式实现一下。
1、产品类的编写
class ICar
{
public:
virtual ~ICar() = 0;
virtual void Speed() = 0;
private:
ICar();
};
class AoDi :public ICar
{
public:
void Speed()
{
// 各自的速度
};
private:
AoDi();
friend class CarFactory;
};
class BaoMa :public ICar
{
public:
void Speed()
{
// 各自的速度
};
private:
BaoMa();
friend class CarFactory;
};
class RiChan :public ICar
{
public:
void Speed()
{
// 各自的速度
};
private:
RiChan();
friend class CarFactory;
};
2、工厂类的编写
class CarFactory
{
public:
enum CarStyle
{
AODI,BAOMA,RICHAN
};
ICar* CreateCar(CarStyle style)
{
ICar*car = nullptr;
switch (style)
{
case CarFactory::AODI:
car = new AoDi;
break;
case CarFactory::BAOMA:
car = new BaoMa;
break;
case CarFactory::RICHAN:
car = new RiChan;
break;
}
return car;
}
private:
};
使用编写好的工厂模式:
CarFactory fac;
ICar* baoma = fac.CreateCar(CarFactory::BAOMA);// 创建一台宝马
ICar* aodi = fac.CreateCar(CarFactory::AODI);// 创建一台奥迪
ICar* richan = fac.CreateCar(CarFactory::RICHAN);// 创建一台日产
baoma->Speed();
aodi->Speed();
richan->Speed();
五、优缺点
1、优点:用户根据自己需求创建不同的子类,模块化清晰,各司其职,分工明确
2、缺点:每增加一个产品,相应的也要增加一个子工厂,加大了额外的开发量。