1.相关概念
- 设计模式:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
- 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
- 耦合:耦合关系是指某两个事物之间如果存在一种相互作用、相互影响的关系,那么这种关系就称"耦合关系"。耦合高是指模快A和模快B之间的关联过高。
- 开闭原则:对扩展开放,对修改封闭。一个软件应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化的。
2.工厂模式分类
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
3.简单工厂模式
- 描述 : 忍辱其名,此模式很简单,而且使用在业务简单的情况下
- 角色:
1.工厂类角色:本角色含有一定的商业逻辑和判断逻辑,根据客户传的不同参数去实现不同的行为,在C++中往往由一个具体的类实现
2.抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在C++中使用抽象类实现
3.具体的产品角色:工厂类所创建的对象就是此角色的实例。在C++中是由一个具体类实现
- 问题:使用开闭原则分析简单工厂模式
- 缺点:扩展性差,需要改变工厂类的代码,违反开闭原则。比如现在工厂中增加了一款车型,只需要增加一个类去继承Car抽象类实现Run方法,在工厂类中添加一个新的匹配项(修改了工厂类的代码,违反了开闭原则)。
- 优点:一定程度上降低了代码的耦合度。当客户端需要产品对象时,只需要将要求告诉工厂,让工厂帮助生产对象,而不必关心生产产品的具体细节。
- 代码实现:
/**
* 简单工厂模式
*/
#include <iostream>
#include <string>
using namespace std;
// 定义车的接口(抽象)
class Car
{
public:
virtual void Run() = 0;
};
// 具体的宝马类(实现)
class BMWCar :public Car
{
public:
virtual void Run()
{
cout << "i am bmw" << endl;
}
};
// 具体的奥迪类(实现)
class AoDiACar : public Car
{
public:
virtual void Run()
{
cout << "i am aodi" << endl;
}
};
// 生产卡车的类
class Factory
{
public:
// 根据客户端不同需求生产宝马或者奥迪
// 客户端传参,工厂类利用参数判断生产那个产品
static Car* ProductCar(string mess)
{
if(mess == "宝马"){
return new BMWCar;
}else if(mess == "奥迪"){
return new AoDiACar;
}else{
cout << "没有您需要的车型" << endl;
return nullptr;
}
}
};
int main()
{
// 客户端
Factory::ProductCar("奥迪")->Run();
Factory::ProductCar("宝马")->Run();
Factory::ProductCar("其他")->Run();
// 释放(C++中没有JVM,堆上的内存需要程序员手动释放,否则会出现内存泄露)
return 0;
}
2.工厂方法模式
- 描述:定义一个创建对象的工厂接口,而不是一个工厂类,让子类去决定实例化哪一个对象,将实际工作交给子类。
- 角色:
1.抽象工厂角色:这是工厂方法模式的核心。是具体工厂角色必须实现的接口或者必须继承的父类。在C++中它由抽象类来实现
2.具体的工厂角色:它含有和具体业务逻辑相关的代码,创建对应的具体产品的对象,在C++中使用具体的类来实现
3.抽象的产品角色:它是具体产品继承的父类或者是实现的接口,在C++中使用抽象类实现
4.具体的产品角色:具体工厂角色所创建的对象就是此角色的实例,在C++中使用具体的类来实现
- 问题:工厂方法模式足以应对我们可能遇到的大部分业务需求。但是当产品种类非常多时会导致过多的具体产品类和具体的工厂类,从而增加系统的负担。
- 缺点:在增加一个新产品的时候,需要增加一个产品类和工厂类,当产品种类过多,会给系统增加负担,并且每个工厂只生产一种产品,太过单一。
- 优点:主要是解决简单工厂在扩展时违反开闭原则的缺点。工厂方法模式的扩展性比较好,比如现在新扩展有个具体产品类(大众),只需要在增加一个具体工厂类去实现工厂接口,创建新的产品类对象,不需要修改其他业务代码。更加符合开闭原则,新增一个产品时,只需要增加相应的具体产品类和相应的工厂类即可;符合单一职责原则,每个具体工厂类只负责创建对应的产品即可。
- 代码实现:
/**
* 工厂方法模式
*/
#include <iostream>
#include <string>
using namespace std;
// 抽象车类
class Car
{
public:
virtual void Run() = 0;
};
// 具体的宝马类(实现)
class BMWCar : public Car
{
public:
virtual void Run()
{
cout << " i am bmw" << endl;
}
};
// 具体的奥迪类(实现)
class AoDiCar : public Car
{
public:
virtual void Run()
{
cout << " i am aodi" << endl;
}
};
// 抽象工厂类
class CarFactory
{
public:
virtual Car* ProductCar() = 0;
};
// 具体生产宝马的工厂(实现)
class BMWFactory : public CarFactory
{
public:
virtual Car* ProductCar()
{
return new BMWCar;
}
};
// 具体生产奥迪的工厂(实现)
class AoDiFactory : public CarFactory
{
public:
virtual Car* ProductCar()
{
return new AoDiCar;
}
};
int main()
{
// 客户端
CarFactory* carA = new AoDiFactory;
carA->ProductCar()->Run();
CarFactory* carB = new BMWFactory;
carB->ProductCar()->Run();
// 释放堆上的内存
return 0;
}
3.抽象工厂模式
- 描述:给客户端提供一个接口,可以创建多个产品族中的产品对象。如果工厂的产品来自多个等级结构,则属于抽象工厂模式。
- 角色:
1.抽象工厂角色:这是抽象工厂的核心,是具体工厂角色必须实现的接口或者必须继承的父类。在C++中使用抽象类实现
2.具体工厂角色:它含有和具体业务逻辑相关的代码,创建对应的具体产品的对象,在C++中使用具体的类实现
3.抽象产品角色:它是具体产品继承的父类或者是实现的接口,在C++中使用抽象类实现
4.具体产品角色:具体工厂角色所创建的对象就是此角色的实例,在C++中使用具体的类实现
- 代码实现:
/**
* 抽象工厂模式
*/
#include <iostream>
#include <string>
using namespace std;
// 卡车抽象类
class Trunk_A
{
public:
virtual void Run() = 0;
};
// 轿车抽象类
class Sedan_A
{
public:
virtual void Run() = 0;
};
// 具体的宝马卡车产品类
class BmwTrunk : public Trunk_A
{
public:
virtual void Run()
{
cout << "宝马卡车" << endl;
}
};
// 具体的宝马轿车产品类
class BmwSedan : public Sedan_A
{
public:
virtual void Run()
{
cout << "宝马轿车" << endl;
}
};
// 具体的奥迪卡车产品类
class AodiTrunk : public Trunk_A
{
public:
virtual void Run()
{
cout << "奥迪卡车" << endl;
}
};
// 具体的奥迪轿车产品类
class AodiSedan : public Sedan_A
{
public:
virtual void Run()
{
cout << "奥迪轿车" << endl;
}
};
// 抽象工厂类
class CarFactory
{
public:
virtual Trunk_A* productTrunk() = 0;
virtual Sedan_A* productSedan() = 0;
};
// 宝马工厂类(一个工厂是生产一个产品族的工厂而不是生产单一的产品)
class BmwFactory : public CarFactory
{
public:
virtual Trunk_A* productTrunk()
{
return new BmwTrunk;
}
virtual Sedan_A* productSedan()
{
return new BmwSedan;
}
};
// 奥迪工厂类
class AodiFactory : public CarFactory
{
public:
virtual Trunk_A* productTrunk()
{
return new AodiTrunk;
}
virtual Sedan_A* productSedan()
{
return new AodiSedan;
}
};
int main()
{
// 客户端
CarFactory* bm = new BmwFactory();
bm->productTrunk()->Run();
bm->productSedan()->Run();
return 0;
}
5.总结
- 无论简单工厂模式、工厂方法模式、还是抽象工厂模式,它们都属于工厂模式,在形式和特点上也是极为相似的,它们的最终目的都是为了解耦。
- 使用工厂模式时,只需要关心降低耦合度的目的是否达到了,其他的则不必关心。