每一种工具、框架、模式的出现必定有存在的理由,但他们的存在是为了解决哪些问题的?
找到了问题的答案,才能在工作中遇到类似的问题的时候学以致用。本文以问题为线索,顺藤摸瓜,谈谈工厂模式的瓜是怎么生长起来的。这个瓜就用一个设计家居销售门店的例子来开始发芽。。
一、设计家居销售门店
如果用代码来开一个家居销售门店,应该怎么实现呢?
1.基本功能实现
class HomeStore(object):
def order(self,money):
if money > 30000:
return Home()
class Home(object):
def designscheme(self):
print("设计方案")
def render(self):
print("方案渲染")
def quote(self):
print("报价")
def product(self):
print("生产")
home_store = HomeStore()
home = home_store.order(50000)
home.designscheme()
home.render()
home.quote()
home.product()
首先创建一个家居销售门店的类,然后类里面创建一个下单的方法order,如果给的钱大于30000,就给顾客返回家居产品,具体实现逻辑如下:
if money > 30000,就调用类Home()创建对象,然后把对象的引用return回来,使用一个变量home 接受这个引用,也就是变量home指向Home()创建的对象;
调用方法home.designscheme()、home.render()、home.quote()、home.product(),实现对象调用类里面的方法;
问题:
家居销售门店的类只能return一种固定通用的家居产品,顾客如果选了不同的定制家居产品,那就实现不了,因为家居销售门店HomeStore类没有定制功能。
2.家居销售门店支持定制不同的家居产品
class HomeStore(object):
def order(self,home_type):
if home_type == '橱柜':
return Cabinet()
if home_type == '衣柜':
return Wardrobe()
class Cabinet(object):
def designscheme(self):
print("定制橱柜方案")
def render(self):
print("渲染橱柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
class Wardrobe(object):
def designscheme(self):
print("定制衣柜方案")
def render(self):
print("渲染衣柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
home_store = HomeStore()
home = home_store.order("橱柜")
home.designscheme()
home.render()
home.quote()
home.product()
在原来的基础功能上,加一个判断:顾客选那种类型的家居产品,就返回对应家居产品类型的类对象的引用。这样家居销售门店可以根据顾客不同的需求,选择不同的家居产品。
问题:
每次添加一个家居产品的类型,家居销售门店的下单order方法就要改代码,也就是加多一个判断,如果家居销售门店的代码和家居产品类型的代码是2个不同的人开发的,家居销售门店每次增加了新的家居产品,一个开发添加了一个新的家居产品类型,就要通知另外一个开发,更改家居销售门店的代码,就是再增加一个判断,否则程序就会挂掉,这就藕合很强,没有解藕。
3.使用函数完成解藕
class HomeStore(object):
def order(self,home_type):
return select_home_type(home_type)
def select_home_type(home_type):
if home_type == '橱柜':
return Cabinet()
if home_type == '衣柜':
return Wardrobe()
class Cabinet(object):
def designscheme(self):
print("定制橱柜方案")
def render(self):
print("渲染橱柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
class Wardrobe(object):
def designscheme(self):
print("定制衣柜方案")
def render(self):
print("渲染衣柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
home_store = HomeStore()
home = home_store.order("橱柜")
home.designscheme()
home.render()
home.quote()
home.product()
使用函数来封装判断家居产品类型的代码,让家居销售门店的类调用判断家居产品类型的函数,这样开发不同家居产品功能的类和判断家居产品类型的函数用一个开发,开发家居销售门店类的是另外一个开发,后面家居产品新增了,只需要一个开发,增加新的家居产品类,函数里面增加新家居产品的判断就可以,不需要通知家居销售门店的开发,这就达到解藕。
问题:
如果程序用面向对象开发,一般尽可能用类,如果一会用函数 ,一会用类,看起来就很懵,这就引出了简单的工厂模式。
4.简单的工厂模式
class HomeStore(object):
def __init__(self):
self.factory = Factory()
def order(self,home_type):
return self.factory.select_home_type(home_type)
class Factory(object):
def select_home_type(home_type):
if home_type == '橱柜':
return Cabinet()
if home_type == '衣柜':
return Wardrobe()
class Cabinet(object):
def designscheme(self):
print("定制橱柜方案")
def render(self):
print("渲染橱柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
class Wardrobe(object):
def designscheme(self):
print("定制衣柜方案")
def render(self):
print("渲染衣柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
home_store = HomeStore()
home = home_store.order("橱柜")
home.designscheme()
home.render()
home.quote()
home.product()
咋一看来,好像只是把生产环节重新创建了一个类,这确实比较像是一种编程习惯,此种解决方式被称作简单工厂模式。
工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体,家居销售门店只负责销售,家居工厂只负责制造。
简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF 23种设计模式。
简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
问题:
现在实现了一个家居销售门店的不同家居产品选择的程序,但如果需要实现不同的家居销售门店,比如欧派、客来福、亚度、月兔的家居销售门店,只能复制粘贴,这样很多代码是重复的。
5.工厂方法模式
多种品牌的家居销售门店
当买家居产品时,有很多种品牌可以选择,比如欧派、客来福、亚度、月兔等,那么此时该怎样进行设计呢?
# 定义一个基本的家居销售门店类
class HomeStore(object):
#仅仅是定义了有这个方法,并没有实现,具体功能,这个需要在子类中实现
def createHome(self, typeName):
pass
def order(self, typeName):
# 让工厂根据类型,生产一种家居产品
self.home = self.createHome(typeName)
self.home.designscheme()
self.home.render()
self.home.quote()
self.home.product()
# 定义一个欧派销售门店类
class oppein(HomeStore):
def createHome(self, typeName):
self.homeFactory = HomeFactory()
return self.homeFactory.createHome(typeName)
# 定义一个生产家居产品的工厂,让其根据具体的订单生产家居产品
class HomeFactory(object):
def createHome(self,typeName):
self.typeName = typeName
if self.typeName == "橱柜":
self.home = Cabinet()
elif self.typeName == "衣柜":
self.home = Wardrobe()
return self.home
# 定义橱柜家居产品类
class Cabinet(object):
# 定义橱柜的方法
def designscheme(self):
print("定制橱柜方案")
def render(self):
print("渲染橱柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
# 定义衣柜家居产品类
class Wardrobe(object):
# 定义衣柜的方法
def designscheme(self):
print("定制衣柜方案")
def render(self):
print("渲染衣柜方案")
def quote(self):
print("报价")
def product(self):
print("生产")
# 创建欧派类的对象
oppeinCabinet = oppein()
# oppeinCabinet对象调用父类的order方法,order方法调用子类的createhome方法,
# 子类的createhome方法创建类HomeFactory的对象,并根据具体家居产品类型通过HomeFactory对象的createHome方法return具体的家居产品的对象
# 调用家居产品对象的方法 designscheme、render、quote、product
suonata.order("橱柜")
工厂模式的历史由来,打个比较通俗的比如:
原始社会自给自足(没有工厂)、农耕社会小作坊(简单工厂,民间酒坊)、工业革命流水线(工厂方法,自产自销)、现代产业链代工厂(抽象工厂,富士康)
而在每一个层次,所关心的对象也不一样,在简单工厂模式下,要想到选择橱柜还是衣柜,在工厂模式下,想到是欧派还是亚度,而抽象工厂模式,平时不怎么用到,也不是很了解,就不展开说了,以后如果遇到使用的场景,再单独拿来谈谈。
最后来看看工厂方法模式
的定义
定义了一个创建对象的
接口
(可以理解为函数),但由子类决定要实例化的类是哪一个,工厂方法模式让类的实例化推迟到子类,抽象的HomeStore提供了一个创建对象的方法createHome,也叫作工厂方法
。子类真正实现这个createHome方法创建出具体产品。 在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。
简单说就是,把一个方法定义在基类里面,不去实现功能,在子类继承这个方法,再去实现功能。
这种在父类里面定义接口(方法名就是接口的意思), 在子类实现这个方法,这种叫做工厂方法设计模型。
最后总结一下,回到开头的问题:
简单工厂模式,解决了耦合强,类、函数写法不统一的问题;
工厂方法模式,解决了如果要开多个品牌的销售门店,如果使用简单工厂模式,只能复制粘贴,代码重复的问题;