设计模式之工厂模式
工厂模式是是实际应用中比较常见的一种创建型设计模式,它提供的是一种最佳的创建对象的方式,工厂模式一般分为简单工厂、工厂方法、抽象工厂三种实现方案。
简单工厂工厂模型因为其不满足设计模式中的开闭原则(简单理解就是做功能扩展时无法做到不修改已有代码功能),所以更适用于产品数量固定且较少的情况且使用者须提供工厂能生产的产品类型,就好比我们去餐馆吃饭我们就可以根据菜单进行菜品选择,餐馆就好比工厂,不同的菜品就是产品;例如软件Navicat中用户选择不同数据库产品进行操作。
工厂方法相比简单工厂满足了开闭原则,更适用产品类个数不确定的情况,使用时只需确定使用的工厂类即可,就好比我先买华为手机可以选择华为专卖店,想买苹果手机就可以去苹果专卖店;例如常见的IDE(VS、Qt等)软件,它们的不同模块就提供了不功能使用,并且我们还能自定义添加一些功能模块使用。
抽象工厂是对工厂方法的升级,解决了简单工厂和工厂方法中子类产品必须是同一类型的问题,适合多种类型产品的创建,但由于产品类型较多结构会相对更加臃肿难于管理。就好比不同地区商业街,你就需要根据地区特点提供不同特色的商铺及产品;例如操作系统就可以看成一个抽象工厂。
总的来说简单工厂、工厂方法及抽象工厂的区别就好比小店、连锁专卖店、商业集团公司;一句话总结就是简单工厂选产品,工厂方法选工厂,抽象工厂先选工厂再选产品。语言可能比较抽象,下面就用他们三个的类关系图来进行区分:
1. 简单工厂的UML图
在简单工厂使用中我们只需先实例化一个工厂类,通过传递产品类型给工厂接口从而获取对应产品,如:
//产品类型需提前定义,也就是上图中的enum ProductType{HUAWEI, XIAOMI};
Factory fac;
Product *proh = fac.createProduct(HUAWEI);
proh->operation();
Product *prox = fac.createProduct(XIAOMI);
prox->operation();
2. 工厂方法的UML图
在工厂方法的使用中我则是需要先实例化具体的产品工厂,我就可以通过其产品接口获取对应产品,如:
Factory *hfac = new HuaWeiFactory;
Product *proh = hfac->createProduct();
proh->operation();
Factory *xfac = new XiaomiFactory;
Product *prox = xfac->createProduct();
prox->operation();
3. 抽象工厂的UML图
抽象工厂的使用则是需要先确定选择实例化工厂类,再确定工厂类创建的产品选择对应创建产品的接口,这里有点类似工厂方法中的使用,不同的是工厂方法中的创建产品接口只有一个无需选择,而这里需要对接口再次进行选择,如:
Factory *hfac = new HWFactory;
Product *proph = hfac->createPhone();
proph->operation();
Product *protb = hfac->createTablet();
protb->operation();
Factory *afac = new APFactory;
Product *proap = afac->createPhone();
proap->operation();
Product *proat = afac->createTablet();
proat->operation();
以上就是工厂模式的三种模型区别及使用的测试代码,具体的模式代码如下:
1. 简单实现一个简单工厂的代码
//抽象产品类
class Product
{
public:
virtual void operation() = 0;
};
//具体产品类定义
class HuaWei : public Product
{
public:
virtual void operation() override
{
cout << "HuaWei operation!" << endl;
}
};
class XiaoMi : public Product
{
public:
virtual void operation() override
{
cout << "XiaoMi operation!" << endl;
}
};
//产品类型枚举定义
enum ProductType{HUAWEI, XIAOMI};
//工厂类的简单定义
class Factory
{
public:
virtual Product *createProduct(ProductType type); //工厂创建产品接口
};
Product * Factory::createProduct(ProductType type)
{
switch(type) //根据用户提供的产品类型实例化产品类
{
case HUAWEI:
return new HuaWei;
case XIAOMI:
return new XiaoMi;
default:
cout << " ProductType error! " << endl;
return nullptr;
}
}
从上面就可以看出简单工厂进行扩展时除了增加新的产品类外还需要对产品类型,工厂的创建产品接口实现进行修改,所以不满足开闭原则。
2. 简单实现一个工厂方法的代码
//抽象产品类
class Product
{
public:
virtual void operation() = 0;
};
//具体产品类定义
class HuaWei : public Product
{
public:
virtual void operation() override
{
cout << "HuaWei operation!" << endl;
}
};
class XiaoMi : public Product
{
public:
virtual void operation() override
{
cout << "XiaoMi operation!" << endl;
}
};
//工厂类的简单定义
class Factory
{
public:
virtual Product *createProduct() = 0; //工厂创建产品接口
};
//具体工厂类的定义
class HuaWeiFactory : public Factory
{
public:
virtual Product *createProduct() override
{
return new HuaWei; //对应工厂就创建对应的产品
}
};
class XiaomiFactory : public Factory
{
public:
virtual Product *createProduct() override
{
return new XiaoMi;
}
};
从上面工厂方法的实现可以看出此时若需要进行扩展,那么直接增加对应的具体产品类与对应的具体工厂类即可,此时扩展操作并不会修改之前的代码,每个类对象都是独立封闭的,所以相比简单工厂就满足的开闭原则,更适合产品类不确定的情况,方便对产品类的扩展与缩减。这里就先仅提供简单工厂与工厂方法的实现代码,抽象工厂实现类似工厂方法,大家可根据简单工厂与工厂方法的实现代码配合其UML图理解实现问题应该不大,若有疑问可留言交流。
注:实际使用中我们的工厂模式还经常会与单例模式结合更具有实际意义,这里也为了方便大家对该设计模式结构的理解,故并没将类的定义与其接口定义分开(采用头文件与源文件的形式),也没去结合其他设计模式,大家在工程中实际使用时应当具体情况具体分析,融会贯通方能大道无形。