工厂模式和抽象工厂

工厂模式和抽象工厂

工厂模式

  • 降低应用维护的复杂度。工厂模式实现了创建者和调用者的分离,使用专门的工厂类

  • 工厂通常有两种形式:
    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()

工厂方法设计模式的实现是一个不属于任何类的单一函数,负责单一种类对象(一个形状、
一个连接点或者其他对象)的创建。
抽象工厂设计模式的实现是同属于单个类的许多个工厂方法用于创建一系列种类的相关对
象(一辆车的部件、一个游戏的环境,或者其他对象).

猜你喜欢

转载自blog.csdn.net/zhuix7788/article/details/88530849