一.工厂方法定义:
工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到子类。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来实现。(部分解决简单工厂中Switch结构引入的开放修改的问题)
《大话设计模式》给出的“计算器”的例子如下图所示:
如上图所示,在客户端(可能是web前端、winform或其他UI)通过用户的操作来决定实例化那种“工厂”。通过“工厂”的统一接口(比如上图中的+CreateOperation)去实例化“产品”。而产品系列又抽象出公共的接口(比如上图中的+GetResult)。这样的好处在于业务代码的编写都是基于抽象接口的:“产品”(比如此例中的算法)的扩展无需修改原服务端的代码(对修改封闭)。只需要新增产品类和对应的工厂类即可(对新增开放)。 一切设计模式都围绕着6大设计原则,其中开放封闭是最重要的原则之一。
二.示例
举的例子为了便于例子,采用的简单明了的案例,不以来任何项目上下文环境。
python示例:
from abc import ABCMeta, abstractmethod
##################################
#服务端代码:
##################################
class CellPhone:
@abstractmethod
def make_a_call(self): pass
class AXON(CellPhone):
def make_a_call(self):
print("ZTE AXON Calling.....")
class IPhoneX(CellPhone):
def make_a_call(self):
print("APPLE IPhoneX Calling.....")
class Vendor:
@abstractmethod
def BuildCellPhone(self): pass
class Apple(Vendor):
def BuildCellPhone(self):
return IPhoneX()
class ZTE(Vendor):
def BuildCellPhone(self):
return AXON()
##################################
#客户端代码:
##################################
Vendors={
"ZTE": ZTE,
"APPLE":Apple
}
vendor_choice =Vendors["APPLE"]()
##################################
#服务端代码-----主业务逻辑
##################################
my_phone = vendor_choice.BuildCellPhone()
my_phone.make_a_call()
ITcl示例:
package require Itcl
#################################################################
#客户端
#################################################################
#相比简单工厂模式,工厂方法模式将Product实例生成的Swicth操作放到了客户端。
set FactorySelect "OnDa"
#选择生产厂家
switch $FactorySelect {
"Apple" {
set Obj_IFactory [Apple #auto]
}
"OnDa" {
set Obj_IFactory [OnDa #auto]
}
}
################################################################
#服务端代码---产品及工厂类定义
################################################################
itcl::class absMP3 {
protected variable FactoryName
public method play
}
itcl::class OnDaMP3 {
inherit absMP3
constructor {} {
set FactoryName "OnDaMP3"
}
public method play {} {
puts "$FactoryName play Song!"
}
}
itcl::class AppleMP3 {
inherit absMP3
constructor {} {
set FactoryName "AppleMP3"
}
public method play {} {
puts "$FactoryName play Song!"
}
}
itcl::class IFactory {
public method BuildMP3
}
itcl::class OnDa {
inherit IFactory
public method BuildMP3 {} {
set Obj_OnDaMP3 [uplevel {namespace which [OnDaMP3 #auto]}]
return $Obj_OnDaMP3
}
}
itcl::class Apple {
inherit IFactory
public method BuildMP3 {} {
set Obj_AppleMP3 [uplevel {namespace which [AppleMP3 #auto]}]
return $Obj_AppleMP3
}
}
################################################################
#服务端代码---业务逻辑
################################################################
#后续MP3品牌、种类的扩充,不会波及这部分业务逻辑,因为业务逻辑的编码都是基于接口的也就减少了BUG引入的风险,忠实了“开放-封闭”原则。
#生产MP3
set Obj_absMP3 [$Obj_IFactory BuildMP3]
#mp3放歌
$Obj_absMP3 play
PS:设计模式6大原则:
设计模式六大原则(1):单一职责原则
设计模式六大原则(2):里氏替换原则
设计模式六大原则(3):依赖倒置原则
设计模式六大原则(4):接口隔离原则
设计模式六大原则(5):迪米特法则
设计模式六大原则(6):开闭原则
找机会再详细分享,此处不展开解释。