C++创建型模式-工厂模式

一、简单工厂模式

1.1 简单工厂模式

简单工厂模式(Simple Factory Pattern)专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类。

简单工厂模式,是一种实例化对象的方式,只要输入需要实例化对象的名字,就可以通过工厂对象的相应工厂函数来制造你需要的对象。

1.2 简单工厂模式的角色

(1)Factory工厂角色(工厂类):

工厂角色即工厂类,是简单工厂模式的核心,负责创建所有实例的内部逻辑,工厂类可以被外界直接调用,创建所需要的产品对象。

(2)Product(抽象产品角色):

抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公告接口。所创建的具体产品对象都是其子类对象。

(3)ConcreteProduct(具体产品角色):

具体产品角色是简单工厂模式的创建目标。每个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的方法。

ProductA、ProductB和ProductC继承自Product虚拟类,Show方法是不同产品的自描述;Factory依赖于ProductA、ProductB和ProductC,Factory根据不同的条件创建不同的Product对象

 依赖关系:箭头指向被依赖的一方

继承关系:

 1.3 简单工厂模式的应用

在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式;
由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。

1.4 简单工厂模式的优缺点

优点:

本着高内聚低耦合的原则,将系统的逻辑部分和功能分开。

缺点:

  • 简单工厂模式会增加系统类的个数,在一定程度上增加了系统的复杂度和理解难度;
  • 系统扩展难,一旦增加新产品,就需要修改工厂逻辑,不利于系统的扩展与维护;简单工厂模式中所有产品的创建都是由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间耦合度高,严重影响了系统的灵活性和扩展性

1.5 简单工厂模式实现

某电视机厂为各个品牌代工生产电视机,可以使用简单工厂的模式来实现。

#include <iostream>
#include <vector>
using namespace std;
  
typedef enum ProductTypeTag
{
  Hair,
  Hisense,
}PRODUCTTYPE;
  
//抽象产品类 TV(电视机类)
class TV
{
public:
  virtual void Show() = 0;
  virtual ~TV(){};//声明析构函数为虚函数,防止内存泄漏
};
 //具体产品类 HairTV(海尔电视类)
class HairTV : public TV
{
public:
  void Show()
  {
    cout<<"I'm HairTV "<<endl;
  }
};
 //具体产品类 HisenseTV(海信电视类)  
class  HisenseTV : public TV
{
public:
  void Show()
  {
    cout<<"I'm HisenseTV"<<endl;
  }
};
  

// 工厂类 TVFactory(电视机工厂类)
class TVFactory
{
public:
  TV* CreateTV(PRODUCTTYPE type)
  {
    switch (type)
    {
    case Hair:
      return new HairTV();
  
    case Hisense:
      return new HisenseTV();
    default:
      return NULL;
    }
  }
};
  
int main(int argc, char *argv[])
{
    // 创建工厂类对象
    TVFactory* myTVFactory = new  TVFactory();
    TV* hairTV = myTVFactory->CreateTV(Hair);
    if (hairTV != NULL)
        hairTV->Show();

    TV* hisenseTV = myTVFactory->CreateTV(Hisense);
    if (hisenseTV != NULL)
        hisenseTV->Show();

    delete  myTVFactory;
    myTVFactory = NULL;

    delete hairTV;
    hairTV = NULL;

    delete hisenseTV;
    hisenseTV = NULL;  
  
    return 0;
}

调试结果:

TVFactory 是工厂类,它是整个系统的核心,提供了静态工厂方法CreateTV(),该方法中包含一个字符串类型的参数,在内部业务逻辑中根据参数值得不同实例化不同的具体产品类,返回相依的对象。简单工厂模式的缺点是 如增加 生成TCL电视时,需要修改工厂类TVFactory。 

小结:

在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式。

二、工厂方法模式

2.1 工厂方法简介

简单工厂模式中最大的缺点是当有新产品要加入系统时,必须要修改工厂类,加入必要的处理逻辑,违背了“开闭原则”

工厂方法模式定义:在工厂模式中,工厂父类负责定义创建产品对象的公告接口,而工厂子类负责生成具体的产品对象目的是将产品的实例化操作延迟到工厂子类中完成,通过工厂子类来确定究竟应该实例化哪一个具体产品类。

2.2 模式结构

 (1)Product (抽象产品)

抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也是产品对象的共同父类或接口。

(2)ConcreteProduct(具体产品)

具体产品实现了抽象产品的接口,某种类型的具体产品由专门的具体工厂创建。

(3)Factory(抽象工厂)

(4)ConcreteFactory(具体工厂)

具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。

2.3 应用    

工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品

1.在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;

2.产品结构较复杂的情况下,可以使用工厂方法模式;

                                                                                                                                                        

2.4 优缺点

优点:系统的扩展性好,符合“开闭原则”  。系统加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品即可。

缺点:在添加新产品时,需要编写新的具体产品类,而且要提供与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统的复杂度。

2.5 举例

简单工厂模式,通过一个电视机代工厂来生产电视机,当需要增加新的品牌的电视机时不得不修该工厂类中的工厂方法,违反了“开闭原则”。

工厂方法模式,将原有的工厂进行分割,为每种品牌的电视机提供一个子工厂,海尔工厂专门负责生产海尔电视机,海信工厂专门负责生产海信电视机,若增加TCL电视,只需要增加一个新的TCL工厂。

#include <iostream>
using namespace std;
 /*抽象产品类 TV(电视机类)*/ 
class TV
{
public:
  virtual void Show() = 0;
 virtual ~TV();//声明析构函数为虚函数,防止内存泄漏
};
 /*具体产品类 HairTV(海尔电视机类)*/ 
class HairTV : public TV
{
public:
  void Show()
  {
    cout<< "I'm HairTV"<<endl;
  }
};
/*具体产品类 HisenseTV(海信电视机类)*/
class HisenseTV : public TV
{
public:
  void Show()
  {
    cout<< "I'm HisenseTV"<<endl;
  }
};
/*工厂类(电视机工厂类)*/  
class TVFactory
{
public:
  virtual TV *CreateTV() = 0;
   virtual ~TVFactory(){};//析构函数声明为虚函数,防止内存泄漏
};
 /*具体工厂类 HairTVFactory(海尔电视机工厂类)*/ 
class HairTVFactory : public TVFactory
{
public:
  TV *CreateTV()
  {
    return new HairTV ();
  }
};
 /*具体工厂类 HisenseTV(海信电视机工厂类)*/ 
class HisenseTVFactory : public TVFactory
{
public:
  TV *CreateTV()
  {
    return new HisenseTV ();
  }
};
  
int main(int argc , char *argv [])
{
  TVFactory *hairTVFactory = new HairTVFactory();
  TV *hairTV = hairTVFactory->CreateTV();
  hairTV->Show();
  
  TVFactory *hisenseTVFactory = new HisenseTVFactory();
  TV *hisenseTV = hisenseTVFactory->CreateTV();
  hisenseTV->Show();
  
  if (hairTVFactory!= NULL)
  {
    delete hairTVFactory;
    hairTVFactory = NULL;
  }
  
  if (hairTV != NULL)
  {
    delete hairTV;
    hairTV = NULL;
  }
  
  if (hisenseTVFactory != NULL)
  {
    delete hisenseTVFactory;
    hisenseTVFactory = NULL;
  }
  
  if (hisenseTV != NULL)
  {
    delete hisenseTV;
    hisenseTV = NULL;
  }
  return 0;
}

运行结果:

三、抽象工厂模式

3.1 抽象工厂模式

抽象工厂模式是工厂方法模式的泛化版,工厂模式是一种特殊的抽象工厂模式,在工厂模式中,每个具体工厂只能生产一种具体的产品,如海尔电视机厂只生产海尔电视机,而抽象工厂方法模式中,一个具体的工厂可以生产多个具体产品。

3.2 模式角色

产品等级结构与产品族:

产品等级结构:

 (1)AbstractFactory(抽象工厂)

抽象工厂用于声明生成抽象产品的方法,在一个抽象工厂中可以定义一组方法,每一个方法对应一个产品等级结构。

(2)ConcreteFactory  (具体工厂)

具体工厂实现了抽象工厂声明的抽象产品的方法,生成一组具体产品

(3)AbstractProduct (抽象产品)

抽象产品为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法。

(4)ConcreteProdunct (具体产品)

具体产品定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。

 3.3 应用

当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。

  1. 适合于产品之间相互关联、相互依赖且相互约束的地方
  2. 需要动态切换产品族的地方

3.4 优缺点

优点:

  1. 抽象工厂模式将产品族的依赖与约束关系放到抽象工厂中,便于管理。
  2. 职责解耦,用户不需要关心一堆自己不关心的细节,由抽象工厂来负责组件的创建
  3. 切换产品族容易,只需要增加一个具体工厂实现,客户端选择另一个套餐就可以了

缺点:

  1. 抽象工厂模式类增加的速度很快,有一个产品族就需要增加一个具体工厂实现,比较繁琐
  2. 产品族难以扩展产品。当产品族中增加一个产品时,抽象工厂接口中需要增加一个函数,对应的所有具体工厂实现都需要修改,修改放大严重。
  3. 抽象工厂并未完全屏蔽创建细节,给出的都是组件。对于这种情况可以结合工厂模式或简单工厂模式一起使用。

3.5 举例

如一个电器工厂可以生产多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视、TCL空调等。相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构。

#include <iostream>
using namespace std;
  
// 抽象产品类类 Television(电视机类)
class Television
{
public:
    virtual void Show() = 0;
    virtual ~Television(){};//析构函数声明为虚函数,防止内存泄漏
};

//具体产品类 HaierTelevision(海尔电视机类)
class HaierTelevision : public Television
{
public:
    void Show()
    {
        cout << "I'm HaierTelevision" << endl;
    }
};
//具体产品类 TCLTelevision(TCL电视机类)
class TCLTelevision : public Television
{
public:
    void Show()
    {
        cout << "I'm TCLTelevision" << endl;
    }
};

// 抽象产品类  AirCondition(空调类)
class AirCondition
{
public:
    virtual void Show() = 0;
    virtual ~AirCondition(){};//析构函数声明为虚函数,防止内存泄漏
};
//具体产品类 HairAirCondition(海尔空调类)
class HairAirCondition : public AirCondition
{
public:
    void Show()
    {
        cout << "I'm HairAirCondition" << endl;
    }
};
//具体产品类 TCLAirCondition(TCL空调类)
class TCLAirCondition : public AirCondition
{
public:
    void Show()
    {
        cout << "I'm TCLAirCondition" << endl;
    }
};

// 抽象工厂类 EFactory(电器工厂类)
class EFactory
{
public:
    virtual Television* CreateTelevision() = 0;
    virtual AirCondition* CreateAirCondition() = 0;
     virtual ~EFactory(){};//析构函数声明为虚函数,防止内存泄漏
};
//具体工厂类 HairFactory(海尔工厂类)
class HairFactory : public EFactory
{
public:
    Television* CreateTelevision()
    {
        return new HaierTelevision();
    }

    AirCondition* CreateAirCondition()
    {
        return new HairAirCondition();
    }
};
//具体工厂类 TCLFactory(TCL工厂类) 
class TCLFactory : public EFactory
{
public:
    Television* CreateTelevision()
    {
        return new TCLTelevision();
    }

    AirCondition* CreateAirCondition()
    {
        return new TCLAirCondition();
    }
};
  
int main(int argc, char *argv[])
{
  EFactory *hairFactory = new HairFactory ();/*实例化工厂抽象类*/
  Television *haierTelevision =hairFactory->CreateTelevision();/*实例化产品抽象类*/
  AirCondition *haierAirCondition = hairFactory->CreateAirCondition();
  
  haierTelevision->Show();
  haierAirCondition->Show();
  
  EFactory *tCLFactory = new TCLFactory ();
  Television *tCLTelevision = tCLFactory->CreateTelevision();
  AirCondition *tCLAirCondition = tCLFactory->CreateAirCondition();
  
  tCLTelevision->Show();
  tCLAirCondition->Show();
  
  if (hairFactory != NULL)
  {
    delete hairFactory;
    hairFactory = NULL;
  }
  
  if (haierTelevision != NULL)
  {
    delete haierTelevision;
    haierTelevision= NULL;
  }
  
  if (tCLAirCondition != NULL)
  {
    delete tCLAirCondition;
    tCLAirCondition = NULL;
  }
  
  if (tCLFactory != NULL)
  {
    delete tCLFactory;
    tCLFactory= NULL;
  }
  
  if (tCLTelevision != NULL)
  {
    delete tCLTelevision;
    tCLTelevision = NULL;
  }
  
  if (tCLAirCondition != NULL)
  {
    delete tCLAirCondition;
    tCLAirCondition = NULL;
  }
}

运行结果:

四、总结

  1. 大家应该已经发现了,其实抽象工厂模式如果只有一个组件的话,其实是退化到了工厂方法模式,也就是没有了产品族的概念,只剩一个产品了,因此简单工厂,工厂方法,抽象工厂这三者之间是有内在联系的,区别只是产品的复杂度。
  2. 抽象工厂的本质是选择产品族,因此大家可以根据这个特征来识别是否可以应用抽象工厂。

简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
 

 

参考文献:

【1】工厂模式(C++实现)工厂模式(C++实现) - 1点er执着 - 博客园

【2】设计模式之简单工厂,工厂方法模式(c++):设计模式之简单工厂,工厂方法模式(c++)_u012219045的专栏-CSDN博客_c++ 工厂方法模式

【3】C++实现设计模式之 — 简单工厂模式C++实现设计模式之 — 简单工厂模式 - jostree - 博客园

【4】 C++设计模式之简单工厂模式实例:https://www.jb51.net/article/55858.htm

【5】C++设计模式之工厂方法模式:https://www.jb51.net/article/55860.htm

【6】C++设计模式之抽象工厂模式:https://www.jb51.net/article/55861.htm

【7】抽象工厂模式和工厂模式的区别: 抽象工厂模式和工厂模式的区别? - 知乎

【8】抽象工厂模式应用场景(24种设计模式优缺点):https://www.haitaoseo.com/960718.html

  • 56
    点赞
  • 287
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
C++ 中使用工厂模式更为常见,因为 C++ 支持面向对象编程。下面是一个 C++ 工厂模式的例子,使用了抽象基类和纯虚函数: ```c++ #include <iostream> using namespace std; // 定义抽象基类 class Shape { public: virtual void draw() = 0; virtual ~Shape() {} }; // 定义具体类 class Rectangle : public Shape { public: void draw() { cout << "This is a rectangle." << endl; } }; class Circle : public Shape { public: void draw() { cout << "This is a circle." << endl; } }; // 定义工厂类 class ShapeFactory { public: Shape* createShape(char type) { switch (type) { case 'r': return new Rectangle(); case 'c': return new Circle(); default: return NULL; } } }; int main() { ShapeFactory factory; Shape* shape1 = factory.createShape('r'); Shape* shape2 = factory.createShape('c'); shape1->draw(); shape2->draw(); delete shape1; delete shape2; return 0; } ``` 在上面的代码中,我们定义了一个抽象基类 `Shape`,它有一个纯虚函数 `draw`,用于在派生类中实现。然后,我们又定义了两个具体类 `Rectangle` 和 `Circle`,它们分别继承自 `Shape`,并实现了 `draw` 函数。 接下来,我们定义了一个工厂类 `ShapeFactory`,它有一个函数 `createShape`,根据类型参数创建相应的对象。如果类型参数是 `'r'`,则创建一个 `Rectangle` 对象;如果类型参数是 `'c'`,则创建一个 `Circle` 对象。注意,这里我们返回的是 `Shape*` 类型,因为 `Rectangle` 和 `Circle` 类都继承自 `Shape`,所以它们可以被转化为 `Shape` 类型的指针。 最后,我们在 `main` 函数中使用工厂类创建了两个对象,并调用它们的 `draw` 函数输出了对象的信息。注意,我们在程序结束时需要手动释放对象占用的内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值