目录
1.概述
工厂模式也是平时我们编程用的比较多的一种行为设计模式,它提供了一种创建对象的最佳方式。工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。
2.结构图
工厂模式的意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个类,工厂模式使一个类的实例化延迟到其子类进行。
所谓创建对象的接口,就是指的工厂方法。对用户来说,不再由A a = new A(); 这种方式来创建A类对象,而是由工厂方法来创建。至于具体创建哪个,可以由具体的工厂方法来决定。
其实有两类工厂类:
1)工厂类本身是一个抽象类,由具体的工厂类来创建不同对象,通常是一个具体的工厂只创建一种对象;UML类图如下:
2)参数化的工厂方法,由不同参数决定创建何种对象,通常一个工厂创建多种对象,UML类图如下:
工厂模式包含以下几个核心角色:
- 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。上图中ICar就是具体车的一个抽象,规定它们的共同的一个接口run()。
- 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。上图中的CBmwCar、CDazhongCar和CPorscheCar都是具体的车型。
- 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。
备注:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
3.实例
抽象车类和具体车类如下:Car.h
#pragma once
#include <iostream>
#include <assert.h>
enum CarType
{
eBMWCar = 0, //宝马车
eJILICar, // 吉利车
eDAZHONGCar, // 大众车
eCHANGANCar, //长安车
ePORSCHECar, //保时捷
};
//抽象对象"车"
class ICar
{
public:
virtual ~ICar() {}
virtual void run() = 0;
virtual bool isNull() = 0;
};
//对象适配器
class CCarAdapter : public ICar
{
public:
void run() override {
assert(0);
}
bool isNull() override {
return false;
}
};
//空对象模式实现
class CNullCar : public ICar
{
public:
void run() override {
assert(0);
}
bool isNull() override {
return true;
}
};
//宝马车
class CBmwCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Bmw car is running...n";
}
};
//吉利车
class CJiliCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Jili car is running...n";
}
};
//大众车
class CDazhongCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Dazhong car is running...n";
}
};
//保时捷豪车
class CPorscheCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Porsche car is running...n";
}
};
//长安车
class CChangAnCar : public CCarAdapter
{
public:
explicit CChangAnCar(int n) :m_n(n) {
}
void run() override {
std::cout << "ChangAn " << m_n << " cars is running...n";
}
private:
int m_n;
};
上面的类 CCarAdapter 是类适配器,关于适配器的更多介绍,请参考博客设计模式之适配器模式-CSDN博客 ,类 CNullCar 是空对象模式的体现,关于空对象模式的更多介绍,请参考设计模式之空对象模式-CSDN博客。
3.1.参数化工厂
CarSimpleFactory.h
#pragma once
#include "Car.h"
#include <memory>
class CCarSimpleFactory
{
public:
//[1]
ICar* create(int type) {
std::unique_ptr<ICar> temp;
switch (type) {
case eBMWCar:
temp.reset(new CBmwCar());
break;
case eJILICar:
temp.reset(new CJiliCar());
break;
case eDAZHONGCar:
temp.reset(new CDazhongCar());
break;
case ePORSCHECar:
temp.reset(new CPorscheCar());
break;
default:
//assert(0);
temp.reset(new CNullCar());
break;
}
return temp.release();
}
//[2]
template<typename Base, typename RCar, typename... Args>
Base* createEx(Args... args) {
return new RCar(std::forward<Args>(args)...);
}
//[3]
template <typename Base, typename RCar, typename... Args>
std::shared_ptr<Base> createEx1(Args... args) {
std::shared_ptr<Base> p(new RCar(std::forward<Args>(args)...));
return p;
}
};
测试代码:
#include <iostream>
#include "Car.h"
#include "CarFactory.h"
int main()
{
std::unique_ptr<ICar> pCar;
std::unique_ptr<CCarFactory> factory(new CCarFactory());
//[1]
std::cout << "Car Factory mode1:n";
pCar.reset(factory->create(eBMWCar)); //宝马
pCar->run();
pCar.reset(factory->create(eDAZHONGCar)); //大众
pCar->run();
pCar.reset(factory->create(eJILICar)); //吉利
pCar->run();
pCar.reset(factory->create(11)); //不生产这种车
if (pCar->isNull()) {
std::cout << "Carfactory not product the 11 type car!!!n";
}
pCar.reset(factory->create(ePORSCHECar)); //保时捷
pCar->run();
return 0;
}
输出:
上面工厂类 CCarSimpleFactory 中的 create() 函数需要根据传入车类型 type生产出具体的车辆,如果系统扩展业务,需要生产别的车型,那就需要修改create()的代码,那就违反了面向对象的设计原则开闭原则;于是我们陆续改进了create函数,编写了 createEx 和 createEx1 函数,利用模版编程,把需要生产的对象和依赖的参数通过模版传入,解决了工厂对车类型的依赖。
3.2.具体工厂类
CarFactory.h
#pragma once
#include "Car.h"
#include <memory>
//抽象车辆工厂
class ICarFactory
{
public:
virtual ~ICarFactory() {}
virtual ICar* create() = 0;
};
class CBmwCarFactory : public ICarFactory
{
public:
ICar* create() override {
return new CBmwCar();
}
};
class CJiliCarFactory : public ICarFactory
{
public:
ICar* create() override {
return new CJiliCar();
}
};
class CDazhongCarFactory : public ICarFactory
{
public:
ICar* create() override {
return new CDazhongCar();
}
};
class CPorscheCarFactory : public ICarFactory
{
public:
ICar* create() override {
return new CPorscheCar();
}
};
每个车型都有自己的工厂,扩展起来也比较容易,无需修改之前的代码;例程比较简单,在这里我就不写了。
4.优缺点
优点:
1) 良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道包建对象的艰辛过程,降低模块间的耦合。
2) 工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成拥抱变化。
3) 屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。在数据库开发中,大家应该能够深刻体会到工厂方法模式的好处:如果使用DBC连接数据库,数据库从MysQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SOL语包是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
4) 工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪采特法则,我不需要的就不要去交流:也符合依赖倒置原则,只依赖产品类的抽象;当然也符合单氏替换原则,使用产品子类替换产品父类,没问题。
缺点:
1) 增加代码复杂度:引入工厂模式会增加代码的复杂度,因为需要定义工厂类来管理对象的创建,同时还需要考虑如何处理异常和错误情况。
2) 违反开闭原则:开闭原则是指软件实体应该对扩展开放,对修改封闭。然而,工厂模式在一定程度上违反了这一原则,因为它在编译时确定了类的结构和关系,导致对新的类结构不适应,难以扩展和维护。
3) 不易调试:由于工厂模式将对象创建的逻辑封装在工厂类中,当出现错误或异常时,调试可能会变得更加困难,因为问题可能出现在隐藏的工厂类中。
本文的源码下载地址:https://download.csdn.net/download/haokan123456789/88746574?spm=1001.2014.3001.5503
原文地址:https://blog.csdn.net/haokan123456789/article/details/135594759
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_58572.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!