设计模式 - (抽象)工厂模式
本文以故事方式介绍工厂模式以及抽象工厂模式的一些知识,本文出现的人名为化名
周末闲来无事,小可爱给大漂亮说想吃烤红薯,让大漂亮做给小可爱吃,大漂亮有点为难了,一个堂堂七尺扣脚大汉,怎么会做烤红薯这种精细的事情呢。但是耐不住小可爱的执着,大漂亮于是决定现学现做,首先大漂亮去网上找了一个合适的教程,准备了一个烤箱和若干红薯。于是大张旗鼓的干了起来,A moment later, 香喷喷,热腾腾,稀软流油的红薯们就出箱了。小可爱就夸大漂亮能干,小可爱和大漂亮吃完这些红薯们,意犹未尽啊,突然心血来潮说,既然我们有了烤箱,我们再烤点其他的小食吧,比如说,烤蛋挞,烤曲奇..., 想想都美味。于是小可爱和大漂亮在烤箱食物的挟持下日渐"膨胀"。
这个烤的过程还是比较漫长枯燥的,大漂亮是一个程序猴子,就想这个过程是不是通过程序也能实现呢?古人云,勤劳致富,从面向对象的角度来看,万物皆可看对象,在用烤箱烤红薯的过程种,大漂亮和小可爱,烤箱,红薯,披萨,曲奇都可看作独立的对象,大漂亮小可爱可以用一个实体类表示,烤箱可以看做是一个加工工厂,用来加工的对象就是红薯,蛋挞,披萨,他们有以下共同点:
1. 都是食物
2. 都可以放在烤箱里烤
所以根据以上分析,大漂亮画出了的这个关系的类图
Oven是工厂角色,只要支持烤的食物都要在Oven里去做
IFood是抽象食物角色,所有的可烤食物都是属于食物,负责所有食物的烤的动作
Pizza和Tart则是具体食物,是Oven所烤的具体的对象
目前看起来貌似很不错哦,可以实现烤箱烤不同的食物,如果以后想烤其他食物,只需要增加具体食物类就行了,不过大漂亮一想,我用烤箱不仅仅用烤的功能的啊,它支持的功能我应该想用就能用啊。如果直接不把这些行为封装起来,既不满足面向对象的开闭原则也不好维护,于是又优化了一下类图如下所示:
如类图所示,和前面的类图的不同的是增加了一个抽象的接口类IBakeFactory, 这个类的作用就是定义这些具有公共行为的接口,正如上面小可爱所说,如果想用烤箱其他功能的话,直接实现这个抽象接口就可以啦,简单又方便。下面是这个类图的详细解释
IBakeFactory是抽象工厂角色 定义烤和支持烤哪些食物的接口
Oven是工厂角色,只要支持烤的食物都要在Oven里去做
IFood是抽象食物角色,所有的可烤食物都是属于食物,负责所有食物的烤的动作
Pizza和Tart则是具体食物,是Oven所烤的具体的对象
这下好了,通过上面的设计,小可爱想烤什么就只要指定食物就行了 打开烤箱就可以去烤它。
人的口腹之欲往往难以停留在某几种食物上,这时大漂亮突然有个疑问,这些食物只能用烤箱去烤吗? 会不会有其他的电器也可以用,于是大漂亮和小可爱仔细研究了一番,发现不仅仅是烤箱有上面的功能,像微波炉,空气炸锅也有类似的功能。如果不研究一下这些功能,以后烤箱不工作了不就完蛋了吗,特别是在急需裹腹的情况下肯定是难以忍受的。于是在大漂亮一番猛如虎的操作下,空气炸锅也安排上了,如果以后再增加微波炉等其他电器,只需把对应食物放进去烤就行了。于是大漂亮又更新了一下类图
优化后得步骤大概分为
#Define the bake factory interface
class IBakeFactory:
def bake(self):
pass
import IBakeFactory as bakeFactory
import Pizza as piz
import Tart as ta
"""
Define the concrete factory
"""
class Oven(bakeFactory.IBakeFactory):
"""
Initialize the class paramerts
:param Self: this is instance of this class
:param foodType: this is the specific food type, it can be Pizza or Tart or other supported type
"""
def __init__(self, foodType):
self._foodType = foodType
"""
Do the bake operation according to the specific food
"""
def bake(self):
food = self.createFood()
print('Bake %s' % food.getName())
"""
Create the concrete food instance according to the input food type
"""
def createFood(self):
#Here create the Pizza instance
if self._foodType == type(piz.Pizza):
return piz.Pizza()
#Here create the Tart instance
if self._foodType == type(ta.Tart):
return piz.Tart()
else:
return piz.Pizza()
import IFood as food
"""
Define the concrete Pizza class
"""
class Pizza(food.IFood):
"""
Get the food name
"""
def getName(self):
return 'Pizza'
import IFood as food
"""
Define the Tart
"""
class Tart(food.IFood):
"""
Get the food name
"""
def getName(self):
return 'Tart'
import Pizza as pizza
import Oven as oven
factory = oven.Oven(type(pizza.Pizza))
factory.bake()
这样一来,小可爱就不用关心怎么去烤了 只需要通过类似点餐的方式,等着吃就行了。