最近在学习设计模式,简单工厂,工厂方法,抽象工厂这几种设计模式看了快两天了,终于差不多弄懂了,这里和大家分享一下个人的理解,不当之处欢迎指正!
简单工厂
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
适用场景
简单工厂模式的适用场景是当系统中存在多个类且这些类相对固定不会经常变动(增加或删除),此情形下可将各个类实例化的逻辑封装到一个工厂类中(也即封装成一个接口),用户只需要调用该接口通过向该接口传递参数就可以实例化对应的类,而不需要知道实例化的具体过程。
优点
这样做的好处是通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。
以下是简单工厂模式的一个实现。
# 生产汽车的工厂, 用于根据参数实例化对应的汽车类
class Factory(object):
@staticmethod
def create_car(car):
car_to_create = {'audi': Audi,'bmw': BMW}
return car_to_create[car]()
# 汽车父类
class Car(object):
def __init__(self):
self._price = 0
def get_price(self): # 获取价格
return self._price
def set_price(self, price): # 设置价格
self._price = price
# 奥迪汽车类
class Audi(Car):
def __init__(self):
self._price = 200000
def run(self):
res = 'Audi is fast!'
return res
# 宝马汽车类
class BMW(Car):
def __init__(self):
self._price = 600000
def run(self):
res = 'BMW is fast than Audi!'
return res
# 车店类向工厂类传递参数实例化对应的汽车
class CarStore(object):
def show(self, car):
car_to_sell = Factory.create_car(car)
price = car_to_sell.get_price()
desc1 = car_to_sell.run()
desc2 = 'it needs %sRMB' % (price)
return desc1+desc2
if __name__ == '__main__':
car_to_buy = CarStore()
res1 = car_to_buy.show('audi')
res2 = car_to_buy.show('bmw')
print(res1)
print(res2)
缺点
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。
工厂方法
前面说到简单工厂模式的问题是当系统中的类增加或减少时需要修改工厂类中的逻辑,但这不符合开闭原则。而工厂方法恰好就是要解决这一问题。
工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
适用场景
第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。
第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
优点
工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品,降低客户端和工厂的耦合性,扩展性较好。
以下是第二种情况下工厂方法的一个实现。
# 具体工厂的父类,描述具体工厂的公共接口
class CarFactory(object):
def create_car(self):
pass
# 奥迪工厂
class AudiFactory(CarFactory):
def create_car(self):
return Audi()
# 宝马工厂
class BMWFactory(CarFactory):
def create_car(self):
return BMW()
class Car(object):
def __init__(self):
self._price = 0
def get_price(self): # 获取价格
return self._price
def set_price(self, price): # 设置价格
self._price = price
# 奥迪汽车类
class Audi(Car):
def __init__(self):
self._price = 200000
def run(self):
res = 'Audi is fast!'
return res
# 宝马汽车类
class BMW(Car):
def __init__(self):
self._price = 600000
def run(self):
res = 'BMW is fast than Audi!'
return res
# 车店类向工厂类传递参数实例化对应的汽车
class CarStore(object):
def __init__(self):
self.factory = None
def show(self, car):
factory = {'audi': AudiFactory,'bmw':BMWFactory}
self.factory = factory[car]()
# 根据参数选择需实例化的工厂
car_to_sell = self.factory.create_car()
# 根据具体工厂实例化汽车
price = car_to_sell.get_price()
desc1 = car_to_sell.run()
desc2 = 'it needs %sRMB' % (price)
return desc1+desc2
if __name__ == '__main__':
car_to_buy = CarStore()
res1 = car_to_buy.show('audi')
res2 = car_to_buy.show('bmw')
print(res1)
print(res2)
缺点
工厂方法的缺点也很明显,每增加一个新的产品都必须增加一个生产该产品的工厂,在一定程度上增加了系统的复杂度,尤其当系统中存在多个系列的产品时。
抽象工厂模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时(以不同品牌的汽车为例,每一品牌即为一个抽象角色),使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
抽象工厂模式是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂。
适用场景
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
优点
1.能较好地支持新增产品族
2.克服了工厂方法中工厂太多的缺点,使同一系列的产品由同一个工厂生产(每一个产品族对应的工厂其实就是一个简单工厂,抽象工厂模式其实是简单工厂和工厂方法的一种结合)
# 抽象工厂,生产汽车工厂的工厂
class AbstractFactory(object):
def get_factory(self, type):
factory_to_create ={'audi':AudiFactory,
'bmw':BMWFactory}
self.factory = factory_to_create[type]()
return self.factory
# 子工厂的父类,描述具体工厂的公共接口
class IFactory(object):
def get_car(self, serials):
pass
# 奥迪工厂
class AudiFactory(IFactory):
def get_car(self, serials):
car_dict = {'a4': AudiA4, 'a6': AudiA6}
self.car = car_dict[serials]()
return self.car
# 宝马工厂
class BMWFactory(IFactory):
def get_car(self, serials):
car_dict = {'x3': BMWX3, 'x6': BMWX6}
self.car = car_dict[serials]()
return self.car
# 车父类
class Car(object):
pass
# 奥迪车父类
class Audi(Car):
pass
# 宝马车父类
class BMW(Car):
pass
# a4类,具体产品类
class AudiA4(Audi):
def show(self):
return 'AudiA4 good!'
# a6类,具体产品类
class AudiA6(Audi):
def show(self):
return 'AudiA6 very good!'
# x3类,具体产品类
class BMWX3(BMW):
def show(self):
return 'BMWX3 nice!'
# x6类,具体产品类
class BMWX6(BMW):
def show(self):
return 'BMWX6 perfect!'
class CarStore(object):
''' 车店类 '''
def __init__(self):
self.factory = AbstractFactory()
# 抽象工厂实例化
def query(self, type, serials):
try:
# 通过用户传参对具体工厂实例化
factory = self.factory.get_factory(type)
# 实例化具体产品
car = factory.get_car(serials)
return car.show()
except KeyError:
return 'we do not have this car!'
if __name__ == "__main__":
store = CarStore()
car_query = store.query('bmw', 'x3')
print(car_query)
其实上述实现还不够直观,如果以不同品牌的电脑商为例(华硕/联想),则这两个厂商即为抽象产品类,华硕工厂和联想工厂即为具体工厂,它们各自生产自家的鼠标/键盘,则键鼠即为具体产品类,这样两家的产品是对应的,会比较直观。
缺点
难以支持新种类的产品(其实是延续了简单工厂模式的缺点)
总结
简单总结一下,简单工厂适合产品类比较固定不会经常性地更改(增加或减少)的情形,工厂方法适合一个系列的产品,抽象工厂适合多个系列的产品。