面向对象设计原则
接口隔离原则:面向对象设计之接口隔离原则-CSDN博客
设计模式
工厂模式 : 设计模式之工厂模式-CSDN博客
迭代器模式:设计模式之迭代器模式-CSDN博客
适配器模式:设计模式之适配器模式-CSDN博客
过滤器模式:设计模式之过滤器模式-CSDN博客
单例模式:设计模式之单例模式-CSDN博客
观察者模式:设计模式之观察者模式-CSDN博客
空对象模式:设计模式之空对象模式-CSDN博客
桥接模式:设计模式之桥接模式-CSDN博客
目录
1.概述
2.结构图
3.实例
4.优缺点
工厂模式也是平时我们编程用的比较多的一种行为设计模式,它提供了一种创建对象的最佳方式。工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。
工厂模式的意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个类,工厂模式使一个类的实例化延迟到其子类进行。
所谓创建对象的接口,就是指的工厂方法。对用户来说,不再由A a = new A(); 这种方式来创建A类对象,而是由工厂方法来创建。至于具体创建哪个,可以由具体的工厂方法来决定。
其实有两类工厂类:
1)工厂类本身是一个抽象类,由具体的工厂类来创建不同对象,通常是一个具体的工厂只创建一种对象;UML类图如下:
2)参数化的工厂方法,由不同参数决定创建何种对象,通常一个工厂创建多种对象,UML类图如下:
工厂模式包含以下几个核心角色:
备注:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
抽象车类和具体车类如下:Car.h
#pragma once
#include
#include
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博客。
CarSimpleFactory.h
#pragma once
#include "Car.h"
#include
class CCarSimpleFactory
{
public:
//[1]
ICar* create(int type) {
std::unique_ptr 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
Base* createEx(Args... args) {
return new RCar(std::forward(args)...);
}
//[3]
template
std::shared_ptr createEx1(Args... args) {
std::shared_ptr p(new RCar(std::forward(args)...));
return p;
}
};
测试代码:
#include
#include "Car.h"
#include "CarFactory.h"
int main()
{
std::unique_ptr pCar;
std::unique_ptr 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 函数,利用模版编程,把需要生产的对象和依赖的参数通过模版传入,解决了工厂对车类型的依赖。
CarFactory.h
#pragma once
#include "Car.h"
#include
//抽象车辆工厂
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();
}
};
每个车型都有自己的工厂,扩展起来也比较容易,无需修改之前的代码;例程比较简单,在这里我就不写了。
优点:
1) 良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道包建对象的艰辛过程,降低模块间的耦合。
2) 工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成拥抱变化。
3) 屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。在数据库开发中,大家应该能够深刻体会到工厂方法模式的好处:如果使用DBC连接数据库,数据库从MysQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SOL语包是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
4) 工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪采特法则,我不需要的就不要去交流:也符合依赖倒置原则,只依赖产品类的抽象;当然也符合单氏替换原则,使用产品子类替换产品父类,没问题。
缺点:
1) 增加代码复杂度:引入工厂模式会增加代码的复杂度,因为需要定义工厂类来管理对象的创建,同时还需要考虑如何处理异常和错误情况。
2) 违反开闭原则:开闭原则是指软件实体应该对扩展开放,对修改封闭。然而,工厂模式在一定程度上违反了这一原则,因为它在编译时确定了类的结构和关系,导致对新的类结构不适应,难以扩展和维护。
3) 不易调试:由于工厂模式将对象创建的逻辑封装在工厂类中,当出现错误或异常时,调试可能会变得更加困难,因为问题可能出现在隐藏的工厂类中。
本文的源码下载地址:https://download.csdn.net/download/haokan123456789/88746574?spm=1001.2014.3001.5503