有多个工厂模式是为了满足不同的需求,接下来我们从需求角度出发来了解每种工厂模式。

我们以为枪械厂和弹药厂为例。玩过《绝地求生》应该都知道,每种枪支的子弹都有其特定规格,不同枪支子弹规格不一样,子弹是无法通用的。比如:

枪支 子弹规格(mm)
M4A1 5.56
AK47 7.62
Kar98K 7.62
UZI 9.00

我们可能有如下生产需求:
点击查看【processon】

  • 产品系列
    • 枪支系列
      • M4A1、AK47、98K、UZI等种类。
    • 弹药系列
      • 5.56、7.62、9.00等种类。
  • 工厂:以生产线划分。
    • 枪械厂,有枪支生产线的工厂。
    • 弹药厂,有弹药生产线的工厂。

      简单工厂模式:很少用到

      适合这种需求:
      工厂只需要负责生产AK47、M4A1这两款枪支,不要生产弹药,未来也不会需要生产新枪支。

从代码上来说就是,工厂需要负责创建固定几个类的对象,这几个类有相同(间接)基类

既然情况这么简单,我们也就不需要去区分什么生产线、什么产品系列了,就那么几个产品,搞这么麻烦干嘛。就一个工厂,直接生产就行了。

UML

点击查看【processon】

代码设计

  1. enum GunType {
  2. GunType_AK47,
  3. GunType_M4A1,
  4. };
  5. struct Gun{
  6. virtual Gun* justShow() = 0; //没子弹,只能用来show
  7. }
  8. struct M4A1 : Gun { //AK47类似。
  9. void Gun* justShow(){ return this; }
  10. };
  11. struct GunFactory {
  12. Gun* produce(GunType t) {
  13. switch (t) {
  14. case M4A1: return new M4A1();
  15. case AK47: return new AK47();
  16. default: return NULL;
  17. }
  18. }
  19. };
  20. int main() {
  21. GunFactory factory;
  22. factory.produce(GunType_AK47)->justShow(); //仅做示范,忽略动态内存泄露的问题
  23. factory.produce(GunType_M4A1)->justShow(); //仅做示范,忽略动态内存泄露的问题
  24. }

工厂方法模式:Factory method

一般情况的需求都比简单工厂复杂,因此简单工厂模式也不列入我们的工厂模式中了。

更一般的需求是:工厂需要负责所有类型枪支的生产包括未来的新型枪支。
从代码上来说就是,工厂需要负责创建某一个基类所有派生类对象

如果按照简单工厂模式,虽然可以满足需求,但是很勉强,第一,因为需要创建的对象类型可能很多,工厂会很臃肿,第二,如果出现新类型,就需要改动工厂,这不是明智的选择。
这时候就需要工厂方法模式了。

UML

点击查看【processon】

代码设计

  1. struct Gun {
  2. virtual Gun* justShow() = 0;
  3. };
  4. struct AK47 : Gun{
  5. Gun* justShow(){ return this; } //还是没有子弹,只能show了。
  6. };
  7. struct GunFactory { //专门负责造枪支
  8. virtual Product *produce() = 0;
  9. };
  10. struct FactoryAK47 : GunFactory { //FactoryM4A1类似。
  11. Gun *produce(){
  12. return new AK47();
  13. }
  14. };
  15. int main() {
  16. GunFactory *factoryAK47 = new FactoryAK47() , *factoryM4A1 = new FactoryM4A1();
  17. factoryAK47->produce(); //多态
  18. factoryM4A1->produce(); //多态
  19. }

抽象工厂模式:Abstract factory

可能还会有比工厂方法更复杂一点的需求,比如:
工厂需要同时负责生产枪支和它对应的弹药,有同学可能会想,为啥不分开工厂生产?我们应该从需求出发,这样的需求是合理,所以我们就应该要满足。
从代码上说就是,工厂的每次创建,需要创建一组不同“系列”的对象,这些对象之间有很紧密的关系。

这时候,就需要抽象工厂模式了。

UML

点击查看【processon】

代码设计

  1. struct Gun {
  2. virtual Gun* load(Bullet*) = 0;
  3. virtual Gun* fire() = 0;
  4. };
  5. struct Bullet {
  6. virtual void shoot() = 0;
  7. };
  8. struct AK47 : Gun { //M4A1类似。
  9. Gun* fire(Bullet*){ //逻辑就不写了,必须要上556的子弹。
  10. return this;
  11. }
  12. Gun* fire(){
  13. return this
  14. }
  15. };
  16. struct Bullet762 : Bullet { //Bullet556类似。
  17. void shoot() { }
  18. };
  19. struct WeaponFactory { //枪支弹药制造商
  20. virtual Gun* produceGun() = 0;
  21. virtual Bullet* produceBullet() = 0;
  22. };
  23. struct FactoryAK47 : WeaponFactory { //FactoryM4A1类似
  24. Gun* produceGun(){
  25. return new AK47();
  26. }
  27. Bullet* produceBullet(){
  28. return new Bullet762();
  29. }
  30. };
  31. int main() {
  32. GunFactory *factoryAK = new FactoryAK(), *factoryM4A1 = new FactoryM4A1();
  33. Gun* pGun47 = factoryAK.produceGun();
  34. Bullet* pBulletAK = factoryAK.produceBullet();
  35. Gun* pM4A1 = FactoryM4A1.produceGun();
  36. Bullet* pBulletM4A1 = FactoryM4A1.produceBullet();
  37. //多态:相同静态类型的Gun、Bullet,fire出来却不一样。
  38. pGun47->load(pBulletAK)->fire();
  39. pM4A1->load(pBulletM4A1)->fire();
  40. }

总结

这几个工厂模式,其实就是满足了生产不同复杂度的对象。

  • 简单工厂模式:生产固定几个类的对象。
  • 工厂方法模式:这个一个基类所有派生类的对象。
  • 抽象工厂模式:一次创建一组对象。