工厂模式
-
降低应用维护的复杂度。工厂模式实现了创建者和调用者的分离,使用专门的工厂类
-
工厂通常有两种形式:
1.工厂方法(Factory Method): 是一个方法,对不同的输入参数返回不同的对象
2.抽象工厂:一组用于创建一系列相关事物对象的工厂方法 -
工厂方法
执行单个函数,传入一个参数,但并不要求知道任何关于对象如何实现以及对象来自哪里的细节。
案例:Django的forms模块支持不同种类的字段(CharField EmailField)的创建和定制(max_length required)
工厂方法可以在必要时创建新的对象,从而提高性能和内存使用率。
如果直接实例化类来创建对象,每次创建新对象就需要分配额外的内存
案例1
生产汽车的工厂,根据不同的品牌生产。
#!/bin/python
class CarFactory:
def create_car(self, brand):
if brand == "Benz":
return Benz()
elif brand == "BWM":
return BWM()
elif brand == "BYD":
return BYD()
else:
return "no type brand, cannot create"
class Benz:
pass
class BWM:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.create_car('Benz')
c2 = factory.create_car('BWM')
print (c1)
print (c2)
运行结果:
<main.Benz instance at 0x7f95b0ad6b00>
<main.BWM instance at 0x7f95b0ad6b48>
改造
一般工厂类同时也是单例类,将其改为单例模式的生产汽车类:
#!/bin/python
class CarFactory:
__obj = None
__init_flag = True
def __new__(cls, *args, **kwargs):
if cls.__obj == None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self):
if CarFactory.__init_flag:
CarFactory.__init_flag = False
def create_car(self, brand):
if brand == "Benz":
return Benz()
elif brand == "BWM":
return BWM()
elif brand == "BYD":
return BYD()
else:
return "no type brand, cannot create"
class Benz:
pass
class BWM:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.create_car('Benz')
c2 = factory.create_car('BWM')
factory2 = CarFactory()
print (factory)
print (factory2)
运行结果:
[root@localhost moderm]# python new_fac.py
<main.CarFactory instance at 0x7f4e5c66cc20>
<main.CarFactory instance at 0x7f4e5c66ccf8>
案例2
文件aa.json
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0003",
"type": "donut",
"name": "Old Fashioned",
"ppu": 0.55,
"batters": {
"batter": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" }
]
},
"topping": [
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
文件aa.xml
<persons>
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
<age>25</age>
<address>
<streetAddress>21 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
<phoneNumber type="fax">646 555-4567</phoneNumber>
</phoneNumbers>
<gender>
<type>male</type>
</gender>
</person>
<person>
<firstName>Jimy</firstName>
<lastName>Liar</lastName>
<age>19</age>
<address>
<streetAddress>18 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
</phoneNumbers>
<gender>
<type>male</type>
</gender>
</person>
<person>
<firstName>Patty</firstName>
<lastName>Liar</lastName>
<age>20</age>
<address>
<streetAddress>18 2nd Street</streetAddress>
<city>New York</city>
<state>NY</state>
<postalCode>10021</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">212 555-1234</phoneNumber>
<phoneNumber type="mobile">001 452-8819</phoneNumber>
</phoneNumbers>
<gender>
<type>female</type>
</gender>
</person>
</persons>
工厂模式代码:
import io
import xml.etree.ElementTree as etree
import json
class JSONConnector:
def __init__(self, filepath):
self.data = dict()
with io.open(filepath, mode='r') 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
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)
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('aa.xml')
#print()
xml_factory = connect_to('aa.xml')
xml_data = xml_factory.parsed_data
liars = xml_data.findall(".//{}[{}='{}']".format('person', 'lastName', 'Liar'))
print ('found: {} persons'.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('aa.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()
最后的 connect_to是对 connector_factory的包装,添加异常处理
抽象工厂
抽象工厂设计模式是抽象方法的一种泛化。
即:一个抽象工厂是一组工厂方法,其中的每个工厂方法负责产生不同种类的对象。
优点:使用工厂方法时从用户视角通常是看不到的,那就是抽象工厂能够通过改变激活的工厂方法动态的改变应用行为。
经典例子:能够让用户在使用应用时改变应用的观感,而不需要终止然后重新启动。
实现:
#!/bin/python
class Frog:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def interact_with(self, obstacle):
print('{} the Frog encounters {} and {}!'.format(self, obstacle, obstacle.action()))
class Bug:
def __str__(self):
return 'a bug'
def action(self):
return 'eats it'
class FrogWorld:
def __init__(self, name):
print (self)
self.player_name = name
def __str__(self):
return '\n\n\t-------Frog World-----'
def make_character(self):
return Frog(self.player_name)
def make_obstacle(self):
return Bug()
class Wizard:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def interact_with(self, obstacle):
print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action()))
class Ork:
def __str__(self):
return 'an evil ork'
def action(self):
return 'kills it'
class WizardWorld:
def __init__(self, name):
print (self)
self.player_name = name
def __str__(self):
return '\n\n\t-------Wizard World-----'
def make_character(self):
return Wizard(self.player_name)
def make_obstacle(self):
return Ork()
class GameEnvironment:
def __init__(self, factory):
self.hero = factory.make_character()
self.obstacle = factory.make_obstacle()
def play(self):
self.hero.interact_with(self.obstacle)
def validate_age(name):
try:
age = raw_input('Welcome {}. How old are you? '.format(name))
age = int(age)
except ValueError as err:
print('Age {} is invalid, please try again...'.format(age))
return (False, age)
return (True, age)
def main():
name = input("Hello, What's your name? ")
valid_input = False
while not valid_input:
valid_input, age = validate_age(name)
game = FrogWorld if age < 18 else WizardWorld
environment = GameEnvironment(game(name))
environment.play()
if __name__ == "__main__":
main()
工厂方法设计模式的实现是一个不属于任何类的单一函数,负责单一种类对象(一个形状、
一个连接点或者其他对象)的创建。
抽象工厂设计模式的实现是同属于单个类的许多个工厂方法用于创建一系列种类的相关对
象(一辆车的部件、一个游戏的环境,或者其他对象).