[学习笔记]设计模式之Factory Method
写在前面
为方便读者,本文已添加至索引:
在上篇笔记Abstract Factory设计模式中,时の魔导士创建了一系列的FoodFactory,并教会了其中一名霍比特人theCook如何去createFood。于是,白雪公主和7个小霍比特人终于能填饱肚子了。但是,美丽的童话世界中一定有着危险潜伏。这时,我们需要有一名霍比特人勇敢地站出来守护善良的公主和她的小伙伴们。很好,就让我们叫他theWarrior,一位武器大师:精通匕首、剑、弓、魔杖甚至AK47……。正因如此,我们需要一个武器工厂生产一整套的装备供他使用。回顾上篇笔记的内容,时の魔导士自然想到抽象工厂的好主意,我们可以有SwordFactory, DaggerFactory, BowFactory......但是有个问题,createWeapon并不能像createFood那样将制作过程硬编码,因为theWarrior会需要不同的武器组合,比如英勇的战士一般配一把利剑和坚固的盾牌,或者像精灵王子莱格拉斯(出自电影:霍比特人2)那样带2把匕首和弓箭。怎么样才好呢?当然Factory Method!其实在抽象工厂篇中,我们已经用到Factory Method来实现抽象工厂了。现在让我们来看看具体的内容吧。
要点梳理
- 目的分类
- 对象创建型模式
- 范围准则
- 类(该模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了)
- 主要功能
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类
- 适用情况
- 当一个类不知道它所必须创建的对象的类的时候
- 当一个类希望由它的子类来指定它所创建的对象的时候
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候参与部分
- 参与部分
- Product:定义工厂方法所创建的对象的接口
- ConcreteProduct:实现Product接口
- Creator:声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct对象;可以调用工厂方法以创建一个Product对象
- ConcreteProduct:重定义工厂方法以返回一个ConcreteProduct实例
- 协作过程
- Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例
- UML图例
示例分析 - 强大的武器工坊
时の魔导士仔细思考了一番,决定先建造一座充满魔法的WeaponFactory,通过引入Factory Method,以使得其具体的子类可以选择这些构件,装配出一套适合theWarrior的武器。我们来看一下这个示例:
1 class WeaponFactory { 2 public: 3 void getWeapon(WeaponSuite* suite); 4 5 //Factory method: 6 virtual Weapon* createWeapon() { return 0; } 7 } 8 9 void WeaponFactory::getWeapon(WeaponSuite* suite) { 10 Weapon* w = createWeapon(); 11 suite->add(w); 12 }
于是我们可以引入一个名为『战士的荣耀』的长剑工厂(Kimi: 是不是很酷!……):
1 class HonorOfFighter : public WeaponFactory { 2 public: 3 HonorOfFighter(); 4 Weapon* createWeapon() { return new Sword(); } 5 }
或者一个名为『卫士的信仰』的盾牌工厂,等等等等:
1 class BliefOfDefender : public WeaponFactory { 2 public: 3 BliefOfDefender(); 4 Weapon* createWeapon() { return new Shield(); } 5 }
为了更清楚地表示上面所说的模型,让我们来看看UML图:
哈哈,这下勇敢的霍比特人就能通过拜访不同的工厂来自由获取自己的战斗武器了。
特点总结
我们来总结下工厂方法模式的特点:
- 工厂方法不再将与特定应用有关的类绑定到我们的代码中。代码仅处理Product接口;因此它可以与用户定义的任何ConcreteProduct类一起使用。
- 为子类提供挂钩(hook)。用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。
- 潜在缺点在于我们可能仅仅为了创建一个特定的ConcreteProduct对象,就不得不创建Creator的子类。
当然,如我最早的笔记中所说,设计模式固然重要,但绝不可照本宣科。不同的设计模式之间往往存在着相互依赖,相辅相成的微妙关系。正如前篇中的Abstract Factory,通常会使用Factory Method来实现,当然也可以用Prototype,只是我们暂时还没有涉及。
抽象工厂模式和工厂方法模式从设计模式的角度来讲,的确是存在差异的。但是在我的这两篇笔记中,有的朋友可能会觉得我的示例中都同时存在着抽象工厂模式和工厂方法模式。没错,但是请还是根据文章的内容,辩证地来看待。
写在最后
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!