作者:闫辉 Email:[email protected]
"""
*这种模式是什么?
在Java和其他语言中,抽象工厂模式用于提供接口,创建相关/依赖的对象,而无需指定对象的实际类。
其思想是,将依赖于业务逻辑、平台选择等因素的对象创建,进行抽象。
在Python中,我们使用的接口是一个简单的callabe,它是“内置”的接口。
在Python中,一般情况下,我们可以简单地使用类本身,来作为那个callable,因为类是Python中的头等对象。
*以下示例代码做了什么?
这个特定的实现,抽象了pet的创建。此创建取决于我们选择的工厂(Dog或Cat,或random_animal)。
这是可行的,因为Dog/Cat和random_animal都遵守一个通用的interface(对象创建和.speak()都是callable)。
现在,应用程序可以抽象地创建pet,稍后根据自己的准则,决定是dog还是cat。
*这种模式的实际应用?
*参考资料:
https://sourcemaking.com/design_patterns/abstract_factory
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
*TL;DR80
提供封装一组单个工厂的方法。
"""
import random
class PetShop(object):
"""A pet shop"""
def __init__(self, animal_factory=None):
"""pet_factory is our abstract factory. We can set it at will."""
self.pet_factory = animal_factory
def show_pet(self):
"""Creates and shows a pet using the abstract factory"""
pet = self.pet_factory()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
class Dog(object):
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat(object):
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Additional factories:
# Create a random animal
def random_animal():
"""Let's be dynamic!"""
return random.choice([Dog, Cat])()
# Show pets with various factories
if __name__ == "__main__":
# A Shop that sells only cats
cat_shop = PetShop(Cat)
cat_shop.show_pet()
print("")
# A shop that sells random animals
shop = PetShop(random_animal)
for i in range(3):
shop.show_pet()
print("=" * 20)
### OUTPUT ###
# We have a lovely Cat
# It says meow
#
# We have a lovely Dog
# It says woof
# ====================
# We have a lovely Cat
# It says meow
# ====================
# We have a lovely Cat
# It says meow
# ====================
"""
*这种模式是什么?
工厂方法模式可用于为a方法创建一个接口,将实现留给可实例化的类。
*以下示例代码做了什么?
该代码显示了一种用英语和希腊语本地化单词的方法。
"getLocalizer"是一个工厂方法,它根据所选择的语言,构造了一个本地化器对象。
本地化器对象是不同类的实例,这些不同类取决于被本地化的语言。
不过,主代码不必担心哪个本地化器被实例化,因为方法"get"与所选择的语言无关,它以同样的方式被调用。
*这种模式的实际应用?
在流行的Web框架Django中,可以看到工厂方法:
http://django.wikispaces.asu.edu/*NEW*+Django+Design+Patterns
例如,在一个网页的联系人表单中,尽管subject和message字段的目的不同,实现也不相同,
但是它们是用同一个表单工厂(CharField())创建的。
*参考文献:
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
https://fkromer.github.io/python-pattern-references/design/#factory-method
https://sourcemaking.com/design_patterns/factory_method
* TL;DR80
无需指定确切的类即可创建对象。
"""
class GreekGetter(object):
"""A simple localizer a la gettext"""
def __init__(self):
self.trans = dict(dog="σκύλος", cat="γάτα")
def get(self, msgid):
"""We'll punt if we don't have a translation"""
return self.trans.get(msgid, str(msgid))
class EnglishGetter(object):
"""Simply echoes the msg ids"""
def get(self, msgid):
return str(msgid)
def get_localizer(language="English"):
"""The factory method"""
languages = dict(English=EnglishGetter, Greek=GreekGetter)
return languages[language]()
if __name__ == '__main__':
# Create our localizers
e, g = get_localizer(language="English"), get_localizer(language="Greek")
# Localize some text
for msgid in "dog parrot cat bear".split():
print(e.get(msgid), g.get(msgid))
### OUTPUT ###
# dog σκύλος
# parrot parrot
# cat γάτα
# bear bear
"""
*这种模式是什么?
它解耦了复杂对象的创建和表示,这样就可以重用相同的过程,从同一对象家族中构建对象。
当您必须将对象的规范与它的实际表示分离时(通常用于抽象),这种模式很有用。
*这个例子做了什么?
第一个例子通过使用抽象的基类来实现构建。
初始化器(__init__方法)指定了必需的步骤,具体的子类实现了这些步骤。
在其他编程语言中,有时必须采用更复杂的做法。
特别是,你不能在C++的构造函数中有多态行为。
请参阅
https://stackoverflow.com/questions/1453131/how-can-i-get-polymorphic-behavior-in-ac-constructor
——这意味着这种Python技术不起作用。所需的多态性,必须由外部已构造的其他类的实例来提供。
一般而言,在Python中这不是必需的,不过,以下包含的第二个例子演示了这种做法。
*实际使用的模式在哪里?
*参考文献:
https://sourcemaking.com/design_patterns/builder
* TL; DR80
解耦复杂对象及其表示的创建。
"""
# Abstract Building
class Building(object):
def __init__(self):
self.build_floor()
self.build_size()
def build_floor(self):
raise NotImplementedError
def build_size(self):
raise NotImplementedError
def __repr__(self):
return 'Floor: {0.floor} | Size: {0.size}'.format(self)
# Concrete Buildings
class House(Building):
def build_floor(self):
self.floor = 'One'
def build_size(self):
self.size = 'Big'
class Flat(Building):
def build_floor(self):
self.floor = 'More than One'
def build_size(self):
self.size = 'Small'
# In some very complex cases, it might be desirable to pull out the building
# logic into another function (or a method on another class), rather than being
# in the base class '__init__'. (This leaves you in the strange situation where
# a concrete class does not have a useful constructor)
class ComplexBuilding(object):
def __repr__(self):
return 'Floor: {0.floor} | Size: {0.size}'.format(self)
class ComplexHouse(ComplexBuilding):
def build_floor(self):
self.floor = 'One'
def build_size(self):
self.size = 'Big and fancy'
def construct_building(cls):
building = cls()
building.build_floor()
building.build_size()
return building
# Client
if __name__ == "__main__":
house = House()
print(house)
flat = Flat()
print(flat)
# Using an external constructor function:
complex_house = construct_building(ComplexHouse)
print(complex_house)
### OUTPUT ###
# Floor: One | Size: Big
# Floor: More than One | Size: Small
# Floor: One | Size: Big and fancy
"""
*这种模式是什么?
这种模式旨在减少一个应用所需的类的数量。它不是依赖于子类,而是通过复制原型实例,在运行时创建对象。
当类的实例只有几个不同状态的组合,且实例化的开销很昂贵时,此模式很有用,因为它可以很容易地派生出新类型的对象。
*这个例子做了什么?
当应用程序中的原型的数量不一样时,保持一个Dispatcher(aka,Registry或Manager)是很有用的。
这允许客户端代码在克隆一个新的实例之前,针对某原型,查询此Dispatcher。
以下代码提供这样的Dispatcher的一个示例,其中包含了三个原型的副本: 'default','objecta'和'objectb'。
* TL; DR80
通过克隆原型创建新的对象实例。
"""
class Prototype(object):
value = 'default'
def clone(self, **attrs):
"""Clone a prototype and update inner attributes dictionary"""
# Python in Practice, Mark Summerfield
obj = self.__class__()
obj.__dict__.update(attrs)
return obj
class PrototypeDispatcher(object):
def __init__(self):
self._objects = {}
def get_objects(self):
"""Get all objects"""
return self._objects
def register_object(self, name, obj):
"""Register an object"""
self._objects[name] = obj
def unregister_object(self, name):
"""Unregister an object"""
del self._objects[name]
def main():
dispatcher = PrototypeDispatcher()
prototype = Prototype()
d = prototype.clone()
a = prototype.clone(value='a-value', category='a')
b = prototype.clone(value='b-value', is_checked=True)
dispatcher.register_object('objecta', a)
dispatcher.register_object('objectb', b)
dispatcher.register_object('default', d)
print([{n: p.value} for n, p in dispatcher.get_objects().items()])
if __name__ == '__main__':
main()
### OUTPUT ###
# [{'objectb': 'b-value'}, {'default': 'default'}, {'objecta': 'a-value'}]
import threading
class Singleton(object):
''''' A python style singleton '''
_instance_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with cls._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
if __name__ == '__main__':
s1=Singleton()
s2=Singleton()
print(id(s1),id(s2),id(s1)==id(s2))