目录
工厂模式用来封装和管理类的创建,最终目的是为了解耦,实现创建者和调用者的分离,隐藏创建类的细节与过程。工厂模式属于创建型模式的一种,它提供了一种创建对象的最佳方式。
工厂模式又分为:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂模式
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类。
简单工厂模式,是一种实例化对象的方式,会通过一个统一的接口创建所需要的对象,只要输入需要实例化对象的名字,就可以通过工厂对象的相应工厂函数来制造你需要的对象。
模式结构
ProductA、ProductB继承自Product虚拟类(抽象基类),method()方法是不同产品的自描述;Factory(工厂类)依赖于ProductA、ProductB,Factory根据不同的条件创建不同的Product对象:
- Factory工厂角色(工厂类):工厂角色即工厂类,是简单工厂模式的核心,负责创建所有实例的内部逻辑,工厂类可以被外界直接调用,创建所需要的产品对象。
- Product(抽象产品角色):抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公告接口。所创建的具体产品对象都是其子类对象。
- ConcreteProduct(具体产品角色):具体产品角色是简单工厂模式的创建目标。每个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的方法。
模式实现
一间手机工厂,为不同品牌的手机公司生产对应品牌的手机,使用简单工厂模式:
1、先来看看抽象产品类(抽象基类):
//抽象产品类 Phone(手机品牌)
class Phone{
public:
virtual void Show() = 0;
virtual ~Phone(){}; //声明虚析构函数,防止内存泄漏
};
2、具体产品类(要保证继承自抽象类):
//具体产品类 xiaomi
class xiaomi_phone : public Phone{
public:
void Show(){
cout<<"I'm xiaomi "<<endl;
}
};
//具体产品类 苹果
class apple_phone : public Phone{
public:
void Show(){
cout<<"I'm apple"<<endl;
}
};
//具体产品类 一加
class oneplus_phone : public Phone{
public:
void Show(){
cout<<"I'm oneplus"<<endl;
}
};
3、生产手机的工厂类:
// 工厂类 PhoneFactory(手机工厂类)
class PhoneFactory{
public:
Phone* CreatePhone(PRODUCTTYPE type){
switch (type)
{
case xiaomi:
return new xiaomi_phone();
case apple:
return new apple_phone();
case oneplus:
return new oneplus_phone();
default:
return NULL;
}
}
};
接下来开始生产:
int main(int argc, char *argv[]){
//先创建工厂类对象
PhoneFactory * myFactory = new PhoneFactory();
Phone* xm = myFactory->CreatePhone(xiaomi); //向工厂唯一接口传递小米品牌
xm->Show();
Phone* app = myFactory->CreatePhone(apple); //向工厂接口传递apple品牌
app->Show();
Phone* one = myFactory->CreatePhone(oneplus); //向工厂接口传递一加品牌
one->Show();
delete xm;
delete app;
delete one;
return 0;
}
生产结果:
PhoneFactory 是工厂类,它是整个系统的核心,提供了静态工厂方法CreatePhone(),该方法中包含一个字符串类型的参数,在内部业务逻辑中根据参数值得不同实例化不同的具体产品类,返回相对应的对象。
小结
优点: 实现了对象的创建和使用的分离,创建完全交给专门的工厂类负责,客户端程序员不需要关心怎么创建,只需要关心如何使用。
缺点:工厂类不够灵活,如果新增一个需要生产的产品,就要修改工厂类,需要修改判断逻辑等。
应用场景: 在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式。
工厂方法模式
简单工厂模式中最大的缺点是当有新产品要加入系统时,必须要修改工厂类,加入必要的处理逻辑,违背了开闭原则(扩展开放,修改关闭) ,没办法做到灵活扩展。
工厂方法模式定义:工厂父类负责定义创建产品对象的公共接口(工厂的抽象接口),而工厂子类负责生成具体的产品对象。
目的是将产品的实例化操作延迟到工厂子类中完成,通过工厂子类来确定究竟应该实例化哪一个具体产品类 。
模式结构
- Product (抽象产品类):抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也是产品对象的共同父类或接口。
- ConcreteProduct(具体产品类):具体产品实现了抽象产品的接口,某种类型的具体产品由专门的具体工厂创建。
- Factory(抽象工厂类)
- ConcreteFactory(具体工厂类):具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。
模式实现
上面的简单工厂模式实现中,通过一个手机代工厂来生产各个品牌的手机,当需要增加新的品牌的手机时不得不修该工厂类中的工厂方法,违反了“开闭原则”。
在工厂方法模式,将原有的工厂进行分割,为每种品牌的手机提供一个子工厂,小米手机工厂专门负责生产小米手机,苹果工厂专门负责生产苹果手机,若增加一加品牌,只需要增加一个新的一加手机子工厂:
1、抽象基类和具体产品类都保持不变:
//抽象产品类 Phone(手机品牌)
class Phone{
public:
virtual void Show() = 0;
virtual ~Phone(){}; //声明析构函数为虚函数,防止内存泄漏
};
//具体产品类 xiaomi
class xiaomi_phone : public Phone{
public:
void Show(){
cout<<"I'm xiaomi "<<endl;
}
};
//具体产品类 苹果
class apple_phone : public Phone{
public:
void Show(){
cout<<"I'm apple"<<endl;
}
};
//具体产品类 一加
class oneplus_phone : public Phone{
public:
void Show(){
cout<<"I'm oneplus"<<endl;
}
};
2、抽象工厂类:
// 抽象手机工厂类 PhoneFactory
class PhoneFactory{
public:
virtual Phone* CreatePhone() = 0; //抽象基类提供接口
virtual ~PhoneFactory(){};
};
3、具体子工厂类:
/xiaomi子工厂类
class xiaomiFactory : public PhoneFactory{
public:
Phone* CreatePhone(){ //返回类型为产品基类类型, 实现基类指针或引用指向子类对象
return new xiaomi_phone();
}
};
//apple子工厂类
class appleFactory : public PhoneFactory{
public:
Phone* CreatePhone(){
return new apple_phone();
}
};
//oneplus子工厂类
class oneplusFactory : public PhoneFactory{
public:
Phone * CreatePhone(){
return new oneplus_phone();
}
};
开始生产:
int main(int argc, char *argv[]){
PhoneFactory *xmfact = new xiaomiFactory(); //new一个小米子工厂对象 , 利用抽象基类工厂(也就是手机总厂)接住对象。
Phone *xm = xmfact->CreatePhone();
xm->Show();
delete xmfact;
delete xm;
PhoneFactory *appfact = new appleFactory();
Phone *app = appfact->CreatePhone();
app->Show();
delete appfact;
delete app;
return 0;
}
生产结果:
小结
工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
优点:系统的扩展性好,符合“开闭原则” 。系统加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品即可。
缺点:在添加新产品时,需要编写新的具体产品类,而且要提供与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统的复杂度。
应用场景:
- 在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;
- 产品结构较复杂的情况下,可以使用工厂方法模式;
抽象工厂模式
抽象工厂模式是工厂方法模式的泛化版,工厂模式是一种特殊的抽象工厂模式。
在工厂模式中,每个具体工厂只能生产一种具体的产品,如小米手机厂只能生产小米品牌的手机,而抽象工厂方法模式中,一个具体的工厂可以生产多个具体的产品,打破了工厂与产品(大类)的一对一的关系。
模式结构
结构上还是四个主要角色:
- Product (抽象产品类):抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也是产品对象的共同父类或接口。
- ConcreteProduct(具体产品类):具体产品实现了抽象产品的接口,某种类型的具体产品由专门的具体工厂创建。
- Factory(抽象工厂类)
- ConcreteFactory(具体工厂类):具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。
模式实现
与工厂方法模式最大的区别就是仅仅新增加了一个新的产品体系,前面是只有手机的产品体系,现在新增加了生产耳机的产品体系。
因此现在的工厂方法(抽象工厂方法)不单单是生产手机,而是新增加了生产耳机,各个工厂子类也去实现(重写)这个方法,从而实现各个子工厂都有了生产手机,与生产耳机的方法:
1、抽象产品类新增了耳机大类:
//抽象产品类 Phone(手机大类)
class Phone{
public:
virtual void Show() = 0;
virtual ~Phone(){};//声明析构函数为虚函数,防止内存泄漏
};
//抽象产品类 Earphone(耳机大类)
class Earphone{
public:
virtual void Show() = 0;
virtual ~Earphone(){};
};
2、具体产品类:
//具体产品类 xiaomi
class xiaomi_phone : public Phone{
public:
void Show(){
cout<<"I'm xiaomi "<<endl;
}
};
//具体产品类 苹果
class apple_phone : public Phone{
public:
void Show(){
cout<<"I'm apple"<<endl;
}
};
//具体产品类 小米耳机
class xiaomi_earphone: public Earphone{
public:
void Show(){
cout<<"I'm xiaomi_earphone"<<endl;
}
};
//具体产品类 苹果耳机
class apple_earphone: public Earphone{
public:
void Show(){
cout<<"I'm apple_earphone"<<endl;
}
};
3、抽象工厂类:
// 抽象工厂类 PhoneFactory
class Factory{
public:
virtual Phone* CreatePhone() = 0;
virtual Earphone* CreateEarphone() = 0 ; //新增耳机这一大品类
virtual ~Factory(){};
};
4、具体工厂类:
//xiaomi子工厂类
class xiaomiFactory : public Factory{
public:
Phone* CreatePhone(){
return new xiaomi_phone();
}
Earphone* CreateEarphone(){
return new xiaomi_earphone();
}
};
//apple子工厂类
class appleFactory : public Factory{
public:
Phone* CreatePhone(){
return new apple_phone();
}
Earphone* CreateEarphone(){
return new apple_earphone();
}
};
生产产品:
int main(int argc, char *argv[]){
Factory *xmfact = new xiaomiFactory(); //new一个小米子工厂对象 , 利用抽象基类工厂(也就是手机总厂)接住对象。
Phone *xmphone = xmfact->CreatePhone(); //小米工厂 生产小米手机
xmphone->Show();
Earphone *xmear = xmfact->CreateEarphone(); //小米工厂 生产小米耳机
xmear->Show();
Factory *appfact = new appleFactory();
Phone *appphone = appfact->CreatePhone(); //小米工厂 生产小米手机
appphone->Show();
Earphone *appear = appfact->CreateEarphone(); //小米工厂 生产小米耳机
appear->Show();
return 0;
}
生产结果:
小结
抽象工厂模式其实只是工厂方法模式的一个扩展,如果抽象工厂模式只有一个产品体系的话,就会退化成工厂方法模式,因此两者没有很大区别。
但是新增一个产品体系,意味着需要对 工厂类进行修改,需要修改原有的工厂逻辑, 包括抽象工厂以及具体子工厂,因此又回到了简单工厂的局面,违反了 开闭原则。
最后总结
抽象工厂模式如果只有一个组件的话,其实是退化到了工厂方法模式,也就是没有了产品族的概念,只剩一个产品了,因此简单工厂,工厂方法,抽象工厂这三者之间是有内在联系的,区别只是产品的复杂度。
抽象工厂的本质是选择产品族,因此可以根据这个特征来识别是否可以应用抽象工厂。
简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。