工厂模式简介
工厂模式解决的问题是:接口选择问题,即让对象自己决定调用什么构造函数来实例化自己,对象本身并不关心该构造函数是什么
工厂模式分类
目录
简单工厂模式
简单工厂模式是工厂模式中最简单的一种,它使用了最简单的方式隐藏了创建对象的细节,一般需要告诉工厂类所需要的类型,工厂类就会调用相应的产品类为用户产生相应的产品。用户使用的是产品的抽象对象,在用时只需要告诉工厂类我需要什么,并不关心工厂类具体如何实现的。就像孙悟空的金箍棒,可以变成刀、剑一些其他东西,孙悟空并不关心金箍棒的内部是如何操作的,只需要要告诉金箍棒我需要什么,它就可以变什么。(例子可能不是很形象啊)
具体实现:
假设现在有一个工厂,可以生产A类产品和B类产品。现在我是工厂总监,我需要检测工厂机器产出A类和B类产品的合格率。所以我需要一些工厂的产品,但什么时候要这需要看我的心情。
#include <iostream>
using namespace std;
class product
{
public:
virtual ~product()
{
}
virtual void makeProduct() = 0;
};
class productA :public product
{
public:
void makeProduct()
{
cout << "我是产品A" << endl;
}
};
class productB :public product
{
public:
void makeProduct()
{
cout << "我是产品B" << endl;
}
};
class simpleFactoryMode
{
public:
product* createProduct(char productType)
{
switch (productType)
{
case 'A' :
{
return new productA();
}
case 'B':
{
return new productB();
}
default:
{
cout << "工厂不能产生这类产品"<<endl;
return 0;
}
}
}
};
int main()
{
simpleFactoryMode* simFact = new simpleFactoryMode();
simFact->createProduct('A')->makeProduct();
simFact->createProduct('B')->makeProduct();
simFact->createProduct('C');
simFact->createProduct('A')->makeProduct();
return 0;
}
上面这例子就是一个简单的简单工厂模式的列子。利用基类指针将用户需要的对象返回,用户只需要告诉工厂类需要什么产品(对象),而不需要关心该产品是如何产生的。
优点:
- (1)隐藏了类的具体实现,将对象的实例化推迟到了子类中进行。
- (2)让用户不用关心如何去实例化对象,而只需要告诉工厂类需要什么对象就可以。
- (3)方便增加新的产品。
- (4)遵循依赖倒转原则(应该针对接口编程,而不是针对实现编程)。
缺点:
- (1)派生类中必须实现基类的所有方法(基类的方法全部为抽象方法,如果派生类中不实现那么该派生类将无法实例化对象)。
- (2)用户只能使用基类中声明的方法,而不能使用派生类自己的方法(使用的是基类的指针)。
- (3)每次增加新的产品时都需要加case语句,违反了“开闭原则”(一个类应该对扩展开放,对修改关闭,即不应该为了扩展类的功能而修改类中原有的代码)
工厂方法模式
上面提到简单工厂模式在增加新产品时违背了“开闭原则”,那么就产生了工厂方法模式来解决这个问题。那如何解决那?将每一中产品的实现分配给具体的工厂。通俗的来说:原来的工厂是一个总工厂,什么产品都在总厂生产,每次增加一种新产品是都需要去增加新的车间,这样车间太多就会导致管理的麻烦。现在厂长觉得车间太麻烦了,于是做了一个新的决定开分工厂,将每种的产品的生产具体到每个新的分工厂,每个分工厂只负责一类产品的生产。当用户需要什么产品是直接告诉对应的工厂生产就可以了。
具体实现:
#include <iostream>
using namespace std;
class product
{
public:
virtual ~product()
{
}
virtual void makeProduct() = 0;
};
class productA :public product
{
public:
void makeProduct()
{
cout << "我是产品A" << endl;
}
};
class productB :public product
{
public:
void makeProduct()
{
cout << "我是产品B" << endl;
}
};
class factoryMethodsMode
{
public:
virtual product* createProduct() = 0;
};
class factory_A :public factoryMethodsMode
{
public:
product* createProduct()
{
cout << "我是分工厂A" << endl;
return new productA();
}
};
class factory_B :public factoryMethodsMode
{
public:
product* createProduct()
{
cout << "我是分工厂B" << endl;
return new productB();
}
};
int main()
{
factory_A* fa = new factory_A();
factory_B* fb = new factory_B();
fa->createProduct()->makeProduct();
fb->createProduct()->makeProduct();
return 0;
}
工厂方法模式利用“分工厂”(具体的产品应该交给具体的工厂的去完成)的方式,满足了开放封闭原则。
优点:
- (1)隐藏产品类的具体细节,用户不需要关心产品如何产生的,只需要告诉那个工厂生产就可以。
- (2)遵循了开放封闭原则。
缺点:
- 工厂方法模式只是改进了简单工厂模式的“开放封闭”的原则,对于其他缺点还没改进。
抽象工厂模式
那么现在存在一个问题:如果A、B产品有两个不同的信号,那么该用哪种模式?如果选择简单工厂模式:那么不满足"开放封闭原则"。选择工厂方法模式的化就需要为每一种产品开一个分工厂,这显然不符合我们平常的认知,我们希望的是一个分工厂可以生产一种产品的所有类型。那么该如何设计那?那就是利用抽象工厂模式。
还有,无论是简单工厂模式还是工厂方法模式都有一个很大的问题,那就用户只能使用基类的方法,不能使用派生类自己的方法,原因是用户使用的是基类的指针,这样就会极大程度上限制了派生类的个性化。即简单工厂模式和工厂方法模式中,派生类必须是同一类型的(只有一个基类)。
而利用抽象工厂模式就可以解决这一问题:让不同的产品去继承不同的基类,依此将每种产品分组。这样就可以在各自的基类中去声明这一组产品的一些方法,在一定程度上解决产品个性化的问题。虽然派生类还是只能使用基类的方法,但在抽象工厂模式中存在多个基类。(这里的基类是指“产品基类”)
具体实现
#include <iostream>
using namespace std;
class product_1
{
public:
virtual void makeProduct() = 0;
};
class product_A1 :public product_1
{
public:
void makeProduct()
{
cout << "Product A1" << endl;
}
};
class product_B1 :public product_1
{
public:
void makeProduct()
{
cout << "Product B1" << endl;
}
};
class product_2
{
public:
virtual void makeProduct() = 0;
};
class product_A2 :public product_2
{
public:
void makeProduct()
{
cout << "Product A2" << endl;
}
};
class product_B2 :public product_2
{
public:
void makeProduct()
{
cout << "Product B2" << endl;
}
};
class abstractFactory
{
public:
virtual product_1* create1() = 0;
virtual product_2* create2() = 0;
};
class factory_A :public abstractFactory
{
public:
product_1* create1()
{
return new product_A1();
}
product_2* create2()
{
return new product_A2();
}
};
class factory_B :public abstractFactory
{
public:
product_1* create1()
{
return new product_B1();
}
product_2* create2()
{
return new product_B2();
}
};
int main()
{
factory_A *fa = new factory_A();
fa->create1()->makeProduct();
fa->create2()->makeProduct();
factory_B *fb = new factory_B();
fb->create1()->makeProduct();
fb->create2()->makeProduct();
return 0;
}
优点:
- (1)让不同的产品去继承不同的基类,从一定程度上增加了程序的灵活性。
缺点:
- (1)代码结构过去臃肿。一个产品类型过程多,就会不好管理。
- (2)如果需要新增加一类产品,就需要修改分工厂的代码,这样就又违背了依赖倒转原则。
简单工厂模式、工厂方法模式和抽象工厂模式的对比
- (1)简单工厂模式采用了简单的方式实现对基类内部信息的隐藏,设计和实现都比较简单,但在增加新产品时会违背开放封闭原则。
- (2)工厂方法模式是针对简单工厂模式的违背开放封闭的改进,采用了分工厂的模式,将具体的产品的实现放在具体的分工厂中。
- (3)抽象工厂模式是针对简单工厂模式和抽象工厂模式只能继承一个基类,从而造成程序不灵活的问题的该进,让一个分工厂生产一种产品的所有类型,但在增加产品类型是会违背依赖倒转原则。