一、简介
工厂模式属于一种创建型模式,它提供一种创建对象的最佳方式,对外不暴露对象的创建,并且通过一个共同的接口获取对象指针。
就像一个工厂根据消费者的需求生产不同的产品,但是并不需要对消费者开放生产方式。消费者只需要使用产品就好,并不需要知晓产品的生成。
适用场景:一般需要生成复杂对象的时候使用工厂模式。但是如果是比较简单的对象,则最好不要使用工厂模式,因为工厂模式需要创建工厂类,增加了系统的复杂性。
二、简单工厂模式
简单工厂模式,封装工厂类,用来提供创建目标对象的方法。
以服装厂为例。假设服装厂可以生产T恤和裤子两种产品。
1、先创建一个衣服的抽象类
//衣服抽象类
class Clothe
{
public:
virtual void Show() = 0;
virtual ~Clothe() {}
};
2、然后,我们创建具体的产品:T恤产品和裤子产品。此类继承于Clothe
//T恤衫产品具体类
class TShirt : public Clothe
{
public:
void Show()
{
cout << "This is T-shirt!" << endl;
}
};
//裤子产品具体类
class Pants : public Clothe
{
public:
void Show()
{
cout << "This is Pants!" << endl;
}
};
3、创建工厂,此工厂会根据“客户”的需求,生产对应的产品(即实例化相应的对象)
typedef enum
{
T_SHIRT,
PANTS
}CLOTHE_TYPE;
//服装工厂
class ClotheFactory
{
public:
Clothe* CreateClothe(CLOTHE_TYPE myType)
{
switch (myType)
{
case CLOTHE_TYPE::T_SHIRT:
return new TShirt();
case CLOTHE_TYPE::PANTS:
return new Pants();
default:
return nullptr;
}
return nullptr;
}
virtual ~ClotheFactory() {}
};
4、最后,我们可以调用这个工厂生产产品了。
需要注意的是,因为clothe其实是new出来的,使用完后需要delete释放掉。
int main()
{
//调用工厂生产裤子
ClotheFactory factory;
Clothe* clothe = factory.CreateClothe(CLOTHE_TYPE::PANTS);
clothe->Show();
//new的对象使用完后需要delete
delete clothe;
clothe = nullptr;
system("pause");
return 0;
}
从简单工厂模式的描述,我们可以看到工厂直接提供了实例化“产品”的方法,即CreateClothe,虽然保护了对象实例化的过程,但是不符合面向对象编程的开闭原则。
开闭原则:在面向对象领域,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”。
假如工厂还需要再增加产品,对于简单工厂模式来说,就需要修改CreateClothe的实现,这违背了开闭原则。所以我们可以使用下面的工厂方法模式来解决这个问题。
三、工厂方法模式
使用抽象类接管工厂的管理,额外定义各个产品单独实现的具体工厂,这些工厂继承了抽象工厂,用来实现具体对象的创建。
以服装厂为例,可以把抽象类理解为一家服装厂公司,这家公司旗下目前有2家工厂,一间只生产T恤,一间只生产裤子。如果有新类型的产品裙子需要增加,就再增加一间工厂,只用来生产裙子,这样就不用改变原来2个工厂的生产内容了,符合开闭原则。
具体代码示例
1、先创建一个衣服的抽象类,此类并不会具体“生产”产品,代码同简单工厂模式
2、然后,我们创建具体的产品:T恤产品和裤子产品,代码同简单工厂模式
3、创建一个抽象类,作为“服装厂公司”,此类作为接口,不再具体实例化产品
//服装工厂
class ClotheFactory
{
public:
virtual Clothe* CreateClothe() = 0;
};
4、定义生产各个产品的工厂
//T恤工厂,只用来生产T恤
class TShirtFactory : public ClotheFactory
{
public:
virtual Clothe* CreateClothe()
{
return new TShirt();
}
};
//裤子工厂,只用来生产裤子
class PantsFactory : public ClotheFactory
{
public:
virtual Clothe* CreateClothe()
{
return new Pants();
}
};
5、可以开始生产了
int main()
{
//调用工厂生产T恤
ClotheFactory* factory = new TShirtFactory();
if (nullptr != factory)
{
Clothe* clothe = factory->CreateClothe();
if (nullptr != clothe)
{
clothe->Show();
//new的对象使用完后需要delete
delete clothe;
clothe = nullptr;
}
}
system("pause");
return 0;
}
【注】如果这家工厂公司需要增加产品裙子,则再增加一个生产裙子的工厂就可以。即再增加如下代码即可
//裙子产品
class Skirt : public Clothe
{
public:
void Show()
{
cout << "This is Skirt!" << endl;
}
};
//裙子工厂,只用来生产裙子
class SkirtFactory : public ClotheFactory
{
public:
virtual Clothe* CreateClothe()
{
return new Skirt();
}
};
可见,工厂方法模式对于简单方法模式来说,增加了系统的复杂度。因为每增加一个产品都要新增一个具体工厂类。对于我们日常写项目来说,需要根据具体情况做取舍。
工厂方法模式还存在一个问题,我们根据抽象工厂ClotheFactory只能去实例化一种类型的产品,即可以实例化继承于Clothe类的TShirt和Pants。而无法创建其他类型(即继承于其他抽象产品类的)对象。
比如,由于疫情来袭,这家服装厂公司决定开辟一条口罩的生产线,用于生产例如N95口罩、医用外科口罩等。由此我们要定义
A、一个口罩抽象产品类
//口罩抽象类
class Mask
{
public:
virtual void equip() = 0;
virtual ~Mask() {};
};
B、N95口罩和外科口罩具体类
//N95口罩具体类
class N95Mask : public Mask
{
virtual void equip()
{
cout << "equipped N95 mask!" << endl;
}
};
//外科口罩具体类
class SurgicalMask : public Mask
{
virtual void equip()
{
cout << "equipped surgical mask!" << endl;
}
};
但是在创建工厂的时候,我们犯了难,现有工厂是无法扩展出对口罩的生产创建的。现有的工厂抽象类ClotheFactory中没有对Mask类的创建方法,所以无论如何,我们都需要在工厂抽象类中修改出对Mask产品的创建方法,即我们需要违背开闭原则,使用下面介绍的抽象工厂模式来解决这个问题。
四、抽象工厂模式
抽象工厂模式适用于需要管理不同类型的类对象的实例化的情况。是工厂方法模式的扩展。抽象工厂模式不符合开闭原则。
以上诉问题例,如果这家工厂打算扩展口罩的生产业务。则需要
1、创建口罩产品抽象类,代码见上诉A
2、创建具体口罩产品的具体实现类,代码见上诉B
3、修改工厂抽象类,此类需要增加生成Mask的方法CreateMask,所以再使用ClotheFactory作为类名不是很合适,改成Factory
//工厂抽象类
class Factory
{
public:
virtual Clothe* CreateClothe(CLOTHE_TYPE type) = 0;
virtual Mask* CreateMask(MASK_TYPE type) = 0;
};
4、生产工厂具体类,具体实现根据传入参数生成对应的clothe或mask
//生产工厂具体类
class ProduceFactory : public Factory
{
public:
virtual Clothe* CreateClothe(CLOTHE_TYPE type)
{
switch (type)
{
case CLOTHE_TYPE::T_SHIRT:
return new TShirt();
case CLOTHE_TYPE::PANTS:
return new Pants();
default:
return nullptr;
}
return nullptr;
}
virtual Mask* CreateMask(MASK_TYPE type)
{
switch (type)
{
case MASK_TYPE::N95_MASK:
return new N95Mask();
case MASK_TYPE::SURGICAL_MASK:
return new SurgicalMask();
default:
return nullptr;
}
return nullptr;
}
};
5、然后,就可以调用生产了
int main()
{
//调用工厂生产T恤
Factory* factory = new ProduceFactory();
if (nullptr != factory)
{
//生产T恤
Clothe* clothe = factory->CreateClothe(CLOTHE_TYPE::T_SHIRT);
if (nullptr != clothe)
{
clothe->Show();
//new的对象使用完后需要delete
delete clothe;
clothe = nullptr;
}
//生产医用外科口罩
Mask* mask = factory->CreateMask(MASK_TYPE::SURGICAL_MASK);
if (nullptr != mask)
{
mask->equip();
delete mask;
mask = nullptr;
}
}
system("pause");
return 0;
}
从上面的逻辑可以看出,如果工厂需要新增生产另一类产品,则必须要对抽象工厂类以及具体实现Create的工厂类进行修改,所以是不符合开闭原则的。
参考&致谢