两个原则
一、开闭原则
开方—封闭原则:对于软件的扩展是开放的,对于软件的修改是封闭的。开发人员应将频繁修改的部分进行抽象,以维护开放封闭原则。
举例:工厂方法模式就是改变了简单工厂模式不能维护开放封闭模式的缺点
对于简单工厂模式,当要增加新的产品时,不单要增加产品类,还要改变工厂类的代码,在工厂类中增加代码;
工厂方法模式,就是将工厂类进行抽象,设计成抽象基类,当要增加新的产品时,增加子工厂类即可,不需要修改工厂类的代码。
二、依赖倒转原则
抽象不依赖于细节,而细节依赖于抽象。即针对接口编程,而不是针对实现编程,高层模块不依赖于底层模块,而是二者都依赖于抽象。
工厂模式
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。
该模式用于封装和管理对象的创建,是一种创建型模式。
分类
可分为三类:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
下面开始详细介绍这几种模式。
简单工厂模式
定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
结构模式图
简单工厂模式角色
- Factory:工厂角色,工厂角色负责实现创建所有实例的内部逻辑。
- Product:抽象产品角色,抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
- ConcreteProduct:具体产品角色,具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
时序图
①先调用工厂类中的静态方法createProduct()
②根据传入产品类型参数,获得具体的产品对象
③返回产品对象并使用
c++代码示例
#include <iostream>
using namespace std;
//简单工厂模式
//Fruit 是抽象产品角色
class Fruit
{
public:
virtual void printInfo() { cout << "Fruit::printInfo\n"; }
};
//Fruit 的派生类的实例对象是被工厂创建出来的,是具体产品角色
class Banana : public Fruit
{
public:
virtual void printInfo() { cout << "Banana::printInfo\n"; }
};
class Apple : public Fruit
{
public:
virtual void printInfo() { cout << "Apple::printInfo\n"; }
};
//水果工厂类,负责创建所有水果类的实例对象,即工厂角色
class FruitFactory
{
public:
static Fruit* createFruit(const string& s)
{
if (s == "apple" || s == "Apple")
{
return new Apple();
}
else if (s == "banana" || s == "Banana")
{
return new Banana();
}
}
};
int main()
{
//工厂模式之简单工厂
//通过工厂类的静态方法得到想要得到的水果(传入水果名称得到水果)
//通过传入“apple”参数得到苹果
Fruit* f = FruitFactory::createFruit("apple");
f->printInfo();
//通过传入“banana”参数得到香蕉
Fruit* f2 = FruitFactory::createFruit("banana");
f2->printInfo();
return 0;
}
测试结果
简单工厂模式优缺点
优点:构造容易,逻辑简单。
通过使用工厂类,外界不再需要关系如何创造各种具体的产品,只要提供一个产品的名称作为参数传给工厂,就可以直接得到一个想要的产品对象,并且可以按照接口规范来调用产品对象的所有功能(方法)。
例:我们使用Fruit* f = FruitFactory::createFruit(“apple”); 在并不知道创建过程的情况下得到苹果(Apple类实例对象), 并且可以通过实例对象调用产品对象的所有方法f->printInfo();
缺点:
①简单工厂模式中的if else判断非常多,完全是Hard Code,如果有一个新产品要加进来,就要同时添加一个新产品类,并且必须修改工厂类,再加入一个 else if 分支才可以,这样就违背了 “开放-关闭原则”中的对修改关闭的准则了。当系统中的具体产品类不断增多时候,就要不断的修改工厂类,对系统的维护和扩展不利。
比如我们要添加新产品西瓜(watermelon),就需要添加一个西瓜类(class Watermelon : public Fruit),
而且需要修改工厂类的createFruit()方法,添加一个else if (s == “watermelon”) 分支。因此违背了“对扩展开发,对修改关闭”的开闭原则了。
②一个工厂类中集合了所有的类的实例创建逻辑,违反了高内聚的责任分配原则,将全部的创建逻辑都集中到了一个工厂类当中,所有的业务逻辑都在这个工厂类中实现。什么时候它不能工作了,整个系统都会受到影响。因此一般只在很简单的情况下应用,比如当工厂类负责创建的对象比较少时。
③简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
使用环境
在以下情况下可以使用简单工厂模式:
工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。