在工厂设计模式中,客户端可以请求一个对象,而无需知道这个对象来自哪里,即使用哪个类来生成这个对象。工厂背后的思想是简化对象的创建,对象的创建和使用解耦。
工厂模式的两种形式:一是工厂方法(Factory Method),对不同的输入参数返回不同的对象;二是抽象工厂,它是一组用于创建一系列相关事物对象的工厂方法。
1. 工厂方法
在工厂方法模式中,执行单个函数,传入一个参数,但并不要求知道任何关于对象如何实现以及对象来自哪里的细节。软件的例子比如Django框架使用工厂方法模式来创建表单字段。Django的forms模块支持不同种类字段(CharField、EmailField)的创建和定制(max_length、required)。
实现例子:对于可读文件格式:XML和Json,对这两种文件进行解析,我们使用Python自带的库(xml.etree.ElementTree和json)来处理XML和Json
import xml.etree.ElementTree as etree
import json
class JsonConnector:
def __init__(self, filepath):
self.data = dict()
with open(filepath, mode='r', encoding='utf-8') as f:
self.data = json.load(f)
@property # 使方法更像一个常规变量,变成类的一个属性,可以使用点符号访问
def parsed_data(self):
return self.data
class XMLConnector:
def __init__(self, filepath):
self.tree = etree.parse(filepath)
@property
def parsed_data(self):
return self.tree
函数connector_factory是一个工厂方法,基于输入文件路径的扩展名返回一个JsonConnector或XMLConnector的实例。
def connector_factory(filepath): # 工厂方法
if filepath.endswith('json'):
connector = JsonConnector
elif filepath.endswith('xml'):
connector = XMLConnector
else:
raise ValueError('Cannot connect to {}'.format(filepath))
return connector(filepath)
# 函数connect_to()对connector_factory()进行包装,添加异常处理
def connect_to(filepath):
factory = None
try:
factory = connector_factory(filepath)
except ValueError as ve:
print (ve)
return factory
def main():
# 确认异常处理是否有效
sqlite_factory = connect_to('data/person.sq3')
print()
xml_facotry = connect_to('data/person.xml')
xml_data = xml_facotry.parsed_data
liars = xml_data.findall(".//{}[{}='{}']".format('person', 'lastName', 'Liar'))
print('found: {} person'.format(len(liars)))
for liar in liars:
print('first name: {}'.format(liar.find('firstName').text))
print('last name: {}'.format(liar.find('lastName').text))
[print('phone number ({})'.format(p.attrib['type']),
p.text) for p in liar.find('phoneNumbers')]
print()
json_factory = connect_to('data/donut.json')
json_data = json_factory.parsed_data
print('found: {} donuts'.format(len(json_data)))
for donut in json_data:
print('name: {}'.format(donut['name']))
print('price: ${}'.format(donut['ppu']))
[print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]
if __name__ == '__main__':
main()
2. 抽象工厂
抽象工厂设计模式是抽象方法的一种泛化。概括来说,一个抽象工厂是一组工厂方法,其中每个工厂方法负责产生不同种类的对象。使用抽象工厂,让对象的创建更容易追踪,将对象的创建与使用解耦,提供优化内存占用和应用性能的潜力
abstract_facotry.py
from abc import ABC, abstractmethod
# 下面的类为工厂类接口及其子
class Creator(ABC):
@abstractmethod
def factory_a(self):
pass
@abstractmethod
def factory_b(self):
pass
@staticmethod
def get_creator(option):
if option == '1':
return ConcreteCreatorA()
elif option == '2':
return ConcreteCreatorB()
class ConcreteCreatorA(Creator):
def factory_a(self):
return ProductA1()
def factory_b(self):
return ProductB1()
class ConcreteCreatorB(Creator):
def factory_a(self):
return ProductA2()
def factory_b(self):
return ProductB2()
# 以下类为产品类接口及其实现子类的代码
class ProductA(ABC):
@abstractmethod
def get_product(self):
pass
class ProductA1(ProductA):
def get_product(self):
return'ProductA1'
class ProductA2(ProductA):
def get_product(self):
return'ProductA2'
class ProductB(ABC):
@abstractmethod
def get_product(self):
pass
class ProductB1(ProductB):
def get_product(self):
return'ProductB1'
class ProductB2(ProductB):
def get_product(self):
return'ProductB2'
def main():
# 获取产品类型与种类
product_class = input("产品种类:").upper() # A B
product_type = input("产品类型:") # 1 2
# 获取具体工厂子类对象
creator = Creator.get_creator(product_type)
# 获得具体的产品对象
if product_class == 'A':
product = creator.factory_a()
print(product.get_product())
elif product_class == 'B':
product = creator.factory_b()
print(product.get_product())
if __name__ == '__main__':
main()