工厂 模式

一、工厂模式是什么?

是C++多态的一种很好的具体表现。通过继承,重写抽象父类的虚函数,并在main函数中通过基类指针指向子类对象的一种编码风格

工厂模式分为三种(简单工厂模式,工厂方法模式,抽象工厂模式)

二、为什么要使用工厂模式?

参考原文链接:https://blog.csdn.net/flyingcloud6/article/details/131352604

解释1、
1.1 如果每次需要的对象构造过程都比较复杂,那么就需要很多行的代码去能去创建一个对象。这样就比较麻烦!

1.2 如果在别的类中又需要创建该对象,那么代码的重复度就很高。

1.3 需要通过一个工具类,把每个对象创建的具体逻辑给隐藏起来,且只对外分别暴露一个调用方法。这样就减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。

1.4 该工具类就是工厂模式思想落地实现的一种具体情况,现在只不过很多框架都会自带工厂模式的实现接口。一般不需要我们自己手写,只需简单配置一下就可以使用了。

解释2、

主要是对对象的创建进行了一个封装;
因此也属于创建型模式。

目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

优点
一个调用者想创建一个对象,只要知道其名称就可以了;
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

三、简单工厂模式(Simple Factory)

结构组成:
工厂类(SimpleFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
抽象产品类(Car):是具体产品类的继承的父类或实现的接口。
具体产品类(BWM\Audi):工厂类所创建的对象就是此具体产品实例。

优点与不足:
优点: 结构简单,管理方式简单

缺点: 扩展性非常差,新增产品的时候,需要去修改工厂类。

举例子:具体产品类BMW、Audi,抽象产品类Car,工厂类SimpleFactory;

抽象产品类:用于存放一类特征相似的实现,并用于定义具体产品类。

工厂类:用于统计所有的特征,可以根据enum类型创建具体的产品对象。

class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};


好处:
可以看到,简单工厂可以做到,让用户创建对象的时候只需要知道对象的名称(BMW、AUDI)就好,而不需要关心创建对象的细节(BMW是如何建造的、型号是什么等等细节)。

不足:

每当我们想要扩展对象的时候(增加BENZ的对象)就需要在SimpleFactory类中添加代码,增加switch后面的case选项。这样一来,就需要修改源代码。灵活性非常的差!!!

那么,能不能做到添加对象的时候,不对现有代码进行修改呢?(也就是我们开发软件时候需要遵守的开-闭原则)

四、工厂模式

一个具体的工厂 生产一个具体的产品

结构组成:
抽象工厂类(Factory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(BMWFactory \AudiFactory ):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Car):它是具体产品继承的父类(基类)。
具体产品类(BWM\Audi):具体工厂所创建的对象,就是此类。

优点与不足
优点: 工厂方法模式抽象出了工厂类,并把具体产品对象的创建放到具体工厂类实现。实现了一个工厂生产一类产品,不需要修改工厂类,只需要增加新的具体工厂类即可。

缺点: 每新增一个产品,就需要增加一个对应的产品的具体工厂类。相比简单工厂模式而言,工厂方法模式需要更多的类定义。

抽象工厂类,提供了创建具体工厂类的纯虚函数,并通过具体工厂类来返回具体产品类;

抽象产品类同上;

举例子:

抽象工厂 + 具体工厂

//工厂方法:
class Factory
{
public:
	virtual Car* createCar(string name) = 0;
};
//宝马工厂
class BMWFactory : public Factory
{
public:
	Car* createCar(string name) 
	{
		return new BMW(name);
	}
};
//奥迪工厂
class AudiFactory : public Factory
{
public:
	Car* createCar(string name)
	{
		return new Audi(name);
	}
};
 
void main()
{
	Factory* bmwfty = new BMWFactory();
	Factory* audifty = new AudiFactory();
 
	Car* p1 = bmwfty->createCar("X6");
	Car* p2 = audifty->createCar("A6");
 
	p1->show();
	p2->show();
     
    // 释放资源
    delete adidasShoes;
    delete adidasProducer;
}

抽象产品 + 具体产品: 

class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};

当我们想要增加新的工厂:比如说奔驰工厂的时候,根本不用去管宝马和奥迪,只需要增加一个新的工厂就行了,所以说是符合了软件设计的          “开闭原则”   : 对已有的功能关闭,对扩展开放

好处:
可以做到不同的产品,在不同的工厂里面创建(模块化非常清晰),能够对现有工厂,以及产品的修改关闭

不足:
实际上,很多产品是有关联关系的,属于一个产品簇,不应该放到不同的工厂里面去创建,这样
一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护

五、抽象工厂模式

一个具体的工厂可生产多个产品。

工厂模式 已经能够满足基本的要求了,但是在实际生活中,比如宝马企业,不止有汽车,还有别的系列产品,比如:车灯、轮胎。。。也就是跟汽车有关的一组产品。这就需要“抽象工厂模式”。

重要区别:

工厂模式:只能生产一个产品。(要么BWM车、要么Audi车)

抽象工厂:可以一下生产一个产品族(里面有很多产品:BWM车\BWM车灯、Audi车\Audi车灯

结构组成(和工厂模式一样):
抽象工厂类厂(
AbstractFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(
BMWFactory\AudiFactory):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(
Car \Light):它是具体产品继承的父类(基类)。
具体产品类(
BMWCar\AudiCar、BmwLight\AudiLight):具体工厂所创建的对象,就是此类。

优点与不足:
优点: 提供一个接口,可以创建多个产品族中的产品对象,同一类的多个产品对象不需要创建多个工厂。

缺点: 相比简单工厂模式而言,抽象工厂模式需要更多的类定义。

举例子:

抽象产品类 + 具体产品类

//系列产品1:
class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};
//系列产品 2:
class Light
{
public:
	virtual void show()=0;
};
class BmwLight :public Light
{
public:
	void show()
	{
		cout << "BMW 的 Light" << endl;
	}
};
class AudiLight :public Light
{
public:
	void show()
	{
		cout << "Audi 的 Light" << endl;
	}
};

抽象工厂类 + 具体工厂类:

//工厂方法 ==>> 抽象工厂(对一组关联关系的产品簇提供产品对象的统一创建)
class Factory
{
public:
	virtual Car* createCar(string name) = 0;//工厂方法  创建汽车
	virtual Light* createLight() = 0;// 工厂方法  创建汽车关联的产品,车灯
};
//宝马工厂
class BMWFactory : public Factory
{
public:
	Car* createCar(string name) 
	{
		return new BMW(name);
	}
	Light* createLight()
	{
		return new BmwLight();
	}
};
//奥迪工厂
class AudiFactory : public Factory
{
public:
	Car* createCar(string name)
	{
		return new Audi(name);
	}
	Light* createLight()
	{
		return new AudiLight();
	}
};
void main()
{
	Factory* bmwfty = new BMWFactory();
	Factory* audifty = new AudiFactory();
 
	Car* p1 = bmwfty->createCar("X6");
	Car* p2 = audifty->createCar("A6");
	p1->show();
	p2->show();
 
	Light* l1 = bmwfty->createLight();
	Light* l2 = audifty->createLight();
	l1->show();
	l2->show();

    delete bmwfty; bmwfty = NULL;
    delete audifty; audifty= NULL;
    delete p1, p2; p1= NULL; p2= NULL;
    delete l1, l2; l1= NULL; l1= NULL;
}

六、应用场景

一、工厂模式应用到以下场景:

1、日志记录器

我们可以使用工厂方法模式来实现日志记录器,将客户端从具体的日志记录器实现中解耦出来,使得客户端只需要关注创建日志记录器的接口,而不用关心具体的实现方式。在这个场景中,我们可以定义一个抽象的Logger工厂接口,具体的文件日志记录器、数据库日志记录器等都实现这个接口并提供自己的创建方法,客户端可以通过调用Logger工厂接口的方法来创建相应的日志记录器。

2、图片读取器

在项目中,我们经常需要读取不同类型的图片,如bmp、jpeg、png等。使用工厂方法模式,我们可以定义一个抽象的ImageReader工厂接口,具体的BmpReader、JpegReader、PngReader等都实现这个接口并提供自己的创建方法,客户端可以通过调用ImageReader工厂接口的方法来创建相应类型的图片读取器。这样一来,我们可以在不同的图片读取器实现中,对图片的解析方式、压缩方式等进行优化和改进,而不需要修改客户端代码。

3、数据库访问器

在数据库操作中,我们经常需要使用到Connection、Statement、ResultSet等对象。使用工厂方法模式,我们可以定义一个抽象的DbConnector工厂接口,具体的MySqlConnection、OracleConnection、SqlServerConnection等都实现这个接口并提供自己的创建方法,客户端可以通过调用DbConnector工厂接口的方法来创建相应类型的数据库访问器。这样一来,我们可以在不同的数据库访问器实现中,对数据库连接、查询性能等进行优化和改进,而不需要修改客户端代码。

4、加密解密器

在项目中,我们经常需要对敏感数据进行加密和解密,如用户密码、信用卡号等。使用工厂方法模式,我们可以定义一个抽象的Encryptor工厂接口,具体的DesEncryptor、AesEncryptor、RsaEncryptor等都实现这个接口并提供自己的创建方法,客户端可以通过调用Encryptor工厂接口的方法来创建相应类型的加密解密器。这样一来,我们可以在不同的加密解密器实现中,对加密算法、安全性等进行优化和改进,而不需要修改客户端代码。

5、GUI控件

在图形界面程序中,我们经常需要使用各种GUI控件,如按钮、文本框、下拉框等。使用工厂方法模式,我们可以定义一个抽象的WidgetFactory工厂接口,具体的WinWidgetFactory、MacWidgetFactory、LinuxWidgetFactory等都实现这个接口并提供自己的创建方法,客户端可以通过调用WidgetFactory工厂接口的方法来创建相应类型的GUI控件。这样一来,我们可以在不同的GUI控件实现中,对界面风格、交互方式等进行优化和改进,而不需要修改客户端代码。

6、代码生成器

在一些代码生成器的开发中,我们需要根据不同的需求生成不同的代码,如Java代码、C++代码等。使用工厂方法模式,我们可以定义一个抽象的CodeGenerator工厂接口,具体的JavaCodeGenerator、CPlusPlusCodeGenerator等都实现这个接口并提供自己的创建方法,客户端可以通过调用CodeGenerator工厂接口的方法来创建相应类型的代码生成器。这样一来,我们可以在不同的代码生成器实现中,对代码风格、编译性能等进行优化和改进,而不需要修改客户端代码。

二、工厂模式 应用场景

(1)通常在使用word办公软件的时候,会根据需要绘制出饼状图,柱状图,折线图等图形。可以提供一个工厂类,根据用户的选择创建出不同类型的图形。

(2)QQ空间背景样式,博客背景样式等都提供了各种风格的样式。提供一个工厂,根据用户选择的具体风格样式,创建出各个不同的背景风格,用来装饰QQ空间。

(3)网页下载工具的开发: 根据需要可以下载新浪网页、腾讯网页、搜狐网页等。根据用户的选择,把网页类型传进工厂,将下载该类型的网页内容。

(4)淘宝购物最后一个支付环节,可以选择货到付款、网上银行、支付宝等类型支付。用户可以选择具体的支付方式完成订单,这也是简单工厂模式的一种应用。

(5)电影院打折算法: VIP5折、学生票5折、成人票正常收费等打折算法。

(6)多功能计算器的开发:封装加减乘除等运算操作(大话设计模式的例子)

(7)在很多游戏场合,游戏角色可以选择各种各样的武器,如:手枪、AK47、步枪、大刀等。

(8)如果电脑上装有QQ输入法、搜狗输入法、微软拼音输入法,用户可以设置使用哪种类型的输入法。类似的还可以设置IE浏览器、谷歌浏览器、火狐浏览器。可以设置word2003或者金山的WPS。这些都可以理解为简单工厂模式的一种运用。

(9)软件公司决策是否开发哪一种产品,银行卡识别、身份证识别还是驾驶证识别。

(10)生活中也有很多类似的工厂: 富士康代工工厂;安踏加工厂;咖啡生产基地;沃尔玛等超市提供各种产品供用户使用;肯德基马当劳等。

                 

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值