Creatial Patterns
Abstract Factory
抽象工厂模式: 提供一个接口创建对象,但不需要指定他们真实的类,适用于创建抽象对象依赖不同的配置、平台选择等
class PetShop:
def __init__(self, animal_factory=None):
self.pet_factory = animal_factory
def show_pet(self):
pet = self.pet_factory()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
class Dog:
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat:
def speak(self):
return "maomao"
def __str__(self):
return "Cat"
if __name__ == "__main__":
cat_shop = PetShop(cat)
cat_shop.show_pet()
Factory
工厂模式: 一个函数创建其他的对象
class DevConfig:
DEBUG = False
class ProdConfig:
DEBUG = True
def get_debug(config='dev'):
config = {
"dev": DevConfig,
"prod": ProdConfig
}
return config[config].DEBUG
if __name__ == "__main__":
get_debug('dev')
Borg
Borg: 多个实例之间分享相同的状态
class Borg:
__shared_state = {} # 类中的私有变量
def __init__(self):
self.__dict__ = self.__shared_state
self.state = "Init"
def __str__(self):
return self.state
class YourBorg(Borg):
pass
if __name__ == "__main__":
b1 = Borg()
b2 = Borg()
b1.state = 'hhh'
b2.state = 'wcg'
print(b1, b2) # wcg wcg
Builder
构造模式: 解耦一个复杂对象的创建和表示,通常抽象
class Building:
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)
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 = 'Smail'
if __name__ == "__main__":
house = House()
flat = Flat()
Lazy_evaluation
惰性求值: 初始化的时候不计算,调用的时候才计算
import functools
class lazy_property:
def __init__(self, func):
self.func = func
functools.update_wrapper(self, func)
def __get__(self, obj, type_):
if obj is None:
return self
val = self.func(obj)
obj.__dict__[self.func.__name__] = val
return val
def lazy_property2(fn):
attr = '_lazy_' + fn.__name__
@property
def _lazy_property(self):
if not hasattr(self, attr):
setattr(self, attr, fn(self))
return getattr(self, attr)
return _lazy_property
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
self.call_count = 0
@lazy_property
def relatives(self):
relatives = "Many relatives"
return relatives
@lazy_property2
def parents(self):
self.call_count += 1
return "Father and mother"
if __name__ == "__main__":
Jhon = Person('Jhon', 'Coder')
Json.name # Jhon
Json.occupation # Coder
Json.__dict__.items() # [('name': 'Json', 'occupation': 'Coder', 'call_count': 0)]
Json.relatives # 'Many relatives'
Json.__dict__.items() # [('relatives': 'Many relatives')]
Json.parents # 'Father and mother'
Json.__dict__.items() # [('_lazy__parents': 'Father and mother' ...)]
Json.parents # 'Father and mother'
Json.call_count # 1 call_count不会变
Pool
池: 保存相同的一组实例
class ObjectPool(object):
def __init__(self, queue, auto_get=False):
self._queue = queue
self.item = self._queue.get() if auto_get else None
def __enter__(self): # 上下文
if self.item is None:
self.item = self._queue.get()
return self.item
def __exit__(self, type, value, traceback):
if self.item is not None:
self._queue.put(self.item)
self.item = None
def __del__(self):
if self.item is not None:
self._queue.put(self.item)
self.item = None
if __name__ == "__main__":
import queue
sample_queue = queue.Queue()
sample_queue.put('yam')
with ObjectPool(sample_queue) as obj:
print('Inside with: {}'.format(obj))
print('Outside with: {}'.format(sample_queue.get()))
# Inside with: yam
# Outside with: yam
Prototype
原型: 通过克隆原型创建实例,减少类
class Prototype:
value = 'dafault'
def clone(self, **attrs):
obj = self.__class__
obj.__dict__.update(attrs)
return obj
class PrototypeDispatcher:
def __init__(self):
self._objects = {}
def get_objects(self):
return self._objects
def register_object(self, name, obj):
self._objects[name] = obj
def unregister_object(self, name):
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('default', d)
dispatcher.register_object('objecta', a)
dispatcher.register_object('objectb', b)
print([{n: p.value} for n, p in dispatcher.get_objects().items()])
# [{'default': 'default'}, {'objecta': 'a-value'}, {'objectb': 'b-value'}]
Structural Patterns
3-tier
3-tier: 分离演示,应用程序处理和数据管理,一层层封装
class Data:
products = {
'milk': {'price': 1.50, 'quantity': 10},
'eggs': {'price': 0.20, 'quantity': 100},
'cheese': {'price': 2.00, 'quantity': 10},
}
def __get__(self, obj, klas):
return {'products': self.products}
class BussinessLogic:
data = Data()
def product_list(self):
return self.data['products'].keys()
def product_information(self, product):
return self.data['products'].get(product, None)
class UI:
def __init__(self):
self.business_logic = BussinessLogic()
def get_product_list(self):
for product in self.business_logic.product_list():
print(product)
def get_prouduct_informatin(self, product):
pass
def main():
ui = UI()
ui.get_product_list()
ui.get_prouduct_informatin('eggs')
adapter
适配器: 通过引入间接层来实现不兼容接口的适配,可以用继承,也可以用dict属性
class Dog:
def __init__(self):
self.name = 'dog'
def bark(self):
return 'wangwang'
class Cat:
def __init__(self):
self.name = 'cat'
def meow(self):
return 'maomao'
class Car:
def __init__(self):
self.name = name
def make_noise(self):
return 'dididi'
class Adapter:
def __init__(self, obj, **adapted_methods):
self.obj = obj
self.__dict__.update(adapted_methods)
def __getattr__(self, attr): # 从obj获取
return getattr(self.obj, attr)
def original_dict(self):
return self.obj.__dict__
def main():
dog = Dog()
dog.__dict__ # {'name': 'Dog'}
a = Adapter(dog, make_noise=dog.bark)
a.__dict__ # {'obj': <__main__.Dog at xxx>, 'make_noise': <bound method Dog.bark of <__main__.Dog at xxx>}
a.bark == a.make_noise # True
a.make_noise() # 'wangwang'
bridge
桥模式: 将抽象和实现分离
class DrawingApi1:
def draw_circle(self, x, y, radius):
print('Api1.circle at {}:{} radius {}'.format(x, y, radius))
class DrawingApi2:
def draw_circle(self, x, y, radius):
print('Api2.circle at {}:{} radius {}'.format(x, y, radius))
class CircleShape:
def __init__(self, x, y, radius, drawing_api):
self._x = x
self._y = y
self._radius = radius
self._drawing_api = drawing_api
def draw(self):
self._drawing_api.draw_circle(self._x, self._y, self._radius)
def scale(self, pct):
self._radius *= pct
def main():
shape = CircleShape(1, 2, 3, DrawingApi1())
shape.draw()
composite
综合模式:让客户端统一处理单个对象和组合
class Graphic:
def render(self):
raise NotImplementedError("You should implement this")
class CompositeGraphic(Graphic):
def __init__(self):
self.graphics = []
def render(self):
for graphic in self.graphics:
graphic.render()
def add(self, graphic):
self.graphics.append(graphic)
def remove(self, graphic):
self.graphics.remove(graphic)
class Ellipse(Graphic):
def __init__(self, name):
self.name = name
def render(self):
print("Ellipse: {}".format(self.name))
def main():
pass
decorator
装饰器模式:不改变实例,动态给对象增加新的功能
class TextTag:
def __init__(self, text):
self._text = text
def render(self):
return self._text
class BoldWrapper(TextTag):
def __init__(self, wrapped):
self._wrapped = wrapped
def redner(self):
return '<b>{}</b>'.format(self._wrapped.render())
class ItalicWrapper(TextTag):
def __init__(self, wrapped):
self._wrapped = wrapped
def render(self):
return '<i>{}</i>'.format(self._wrapped.render())
if __name__ == '__main__':
simple_hello = TextTag('hello, world')
special_hello = ItalicWrapper(BoldWrapper(simple_hello))
simple_hello.render() # hello, world
special_hello.render() # <i><b>hello, world</b></i>
facade
facade: 提供一个简单统一的接口来隐藏复杂的系统
class CPU:
def freeze(self):
pass
def jump(self):
pass
def execute(self):
pass
class Memory:
def load(self):
pass
class Computer:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
def start(self):
self.cpu.freeze()
self.memory.load()
self.cpu.jump()
self.cpu.execute()
flyweight
flyweight: 最小化对象的数量,对象池
import weakref
class Card:
_pool = weakref.WeakValueDictionary() # 弱引用, 1 解决交叉引用 2 剩下的引用是弱映射对象所持有的弱引用时,会垃圾回收
def __new__(cls, value, suit):
obj = cls._pool.get(value + suit)
if obj is None:
obj = object.__new__(Card)
cls._pool[value + suit] = obj
obj.value, obj.suit = value, suit
return obj
def __repr__(self):
return "<Card: %s%s>" % (self.value, self.suit)
front_controller
front_controller: 提供一个集中的入口点来管理和控制请求处理
# 类似django
class MobileView:
def get(self):
print('')
class TableView:
def get(self):
print('')
class Dispatcher:
def __init__(self):
self.moblie_view = MobileView()
self.tablet_view = TableView()
def dispatch(self, request):
if request.type == Request.mobile_type:
self.moblie_view.get()
elif reqest.type == request.tablet_type:
self.tablet_view.get()
else:
print('')
class RequestController:
def __init__(self):
self.dispatcher = Dispatcher()
def dispatch_request(self, request):
if isinstance(request, Requeset):
self.dispatcher.dispatch(request)
else:
print('')
class Request:
mobile_type = 'mobile'
tablet_type = 'tablet'
def __init__(self, request):
self.type = None
request = request.lower()
if request == self.mobile_type:
self.type = self.mobile_type
elif request == self.tablet_type:
self.type = self.tablet_type
mvc
mvc: model-view-controller
class Model(object):
def __iter__(self):
raise NotImplementedError
def get(self, item):
"""Returns an object with a .items() call method
that iterates over key,value pairs of its information."""
raise NotImplementedError
@property
def item_type(self):
raise NotImplementedError
class ProductModel(Model):
class Price(float):
"""A polymorphic way to pass a float with a particular
__str__ functionality."""
def __str__(self):
return "{:.2f}".format(self)
products = {
'milk': {'price': Price(1.50), 'quantity': 10},
'eggs': {'price': Price(0.20), 'quantity': 100},
'cheese': {'price': Price(2.00), 'quantity': 10},
}
item_type = 'product'
def __iter__(self):
for item in self.products:
yield item
def get(self, product):
try:
return self.products[product]
except KeyError as e:
raise KeyError((str(e) + " not in the model's item list."))
class View(object):
def show_item_list(self, item_type, item_list):
raise NotImplementedError
def show_item_information(self, item_type, item_name, item_info):
"""Will look for item information by iterating over key,value pairs
yielded by item_info.items()"""
raise NotImplementedError
def item_not_found(self, item_type, item_name):
raise NotImplementedError
class ConsoleView(View):
def show_item_list(self, item_type, item_list):
print(item_type.upper() + ' LIST:')
for item in item_list:
print(item)
print('')
@staticmethod
def capitalizer(string):
return string[0].upper() + string[1:].lower()
def show_item_information(self, item_type, item_name, item_info):
print(item_type.upper() + ' INFORMATION:')
printout = 'Name: %s' % item_name
for key, value in item_info.items():
printout += ', ' + self.capitalizer(str(key)) + ': ' + str(value)
printout += '\n'
print(printout)
def item_not_found(self, item_type, item_name):
print('That %s "%s" does not exist in the records' % (item_type, item_name))
class Controller(object):
def __init__(self, model, view):
self.model = model
self.view = view
def show_items(self):
items = list(self.model)
item_type = self.model.item_type
self.view.show_item_list(item_type, items)
def show_item_information(self, item_name):
try:
item_info = self.model.get(item_name)
except Exception:
item_type = self.model.item_type
self.view.item_not_found(item_type, item_name)
else:
item_type = self.model.item_type
self.view.show_item_information(item_type, item_name, item_info)
proxy
proxy: 提供复制资源的接口
from __future__ import print_function
import time
class SalesManager:
def talk(self):
print("Sales Manager ready to talk")
class Proxy:
def __init__(self):
self.busy = 'No'
self.sales = None
def talk(self):
print("Proxy checking for Sales Manager availability")
if self.busy == 'No':
self.sales = SalesManager()
time.sleep(0.1)
self.sales.talk()
else:
time.sleep(0.1)
print("Sales Manager is busy")
class NoTalkProxy(Proxy):
def talk(self):
print("Proxy checking for Sales Manager availability")
time.sleep(0.1)
print("This Sales Manager will not talk to you", "whether he/she is busy or not")
Behavioral Patterns
chain_of_responsibility
chain_of_responsibility : 在请求的发送者和请求解耦
import abc
class Handler(metaclass=abc.ABCMeta):
def __init__(self, successor=None):
self.successor = successor
def handle(self, request):
res = self.check_range(request)
if not res and self.successor:
self.successor.handle(request)
@abc.abstractclassmethod
def check_range(self, request):
pass
class ConcreteHandler0(Handler):
@staticmethod
def check_range(request):
if 0 <= request < 10:
return True
class ConcreteHandler1(Handler):
start, end = 10, 20
def check_range(self, request):
if self.start <= request <= self.end:
return True
class ConcreteHandler2(Handler):
def check_range(self, request):
start, end = self.get_interval_from_db()
if start <= request < end:
return True
@staticmethod
def get_interval_from_db():
return (20, 30)
class FallbackHandler(Handler):
@staticmethod
def check_range(request):
return False
catalog
catalog: 根据传入的参数使用不同的静态方法
class Catalog(object):
"""catalog of multiple static methods that are executed depending on an init
parameter
"""
def __init__(self, param):
# dictionary that will be used to determine which static method is
# to be executed but that will be also used to store possible param
# value
self._static_method_choices = {'param_value_1': self._static_method_1, 'param_value_2': self._static_method_2}
# simple test to validate param value
if param in self._static_method_choices.keys():
self.param = param
else:
raise ValueError("Invalid Value for Param: {0}".format(param))
@staticmethod
def _static_method_1():
print("executed method 1!")
@staticmethod
def _static_method_2():
print("executed method 2!")
def main_method(self):
"""will execute either _static_method_1 or _static_method_2
depending on self.param value
"""
self._static_method_choices[self.param]()
chaining_method
chaining_method: 继续回调下一个方法
class Person:
def __init__(self, name, action):
self.name = name
self.action = action
def do_action(self):
return self.action
class Action:
def __init__(self, name):
self.name = name
def amount(self, val):
return self
def stop(self):
print('then stop')
def main():
move = Action('move')
person = Person('Jack', move)
person.do_action().amount('5m').stop()
command
command: 绑定一个命令和参数来调用
class MoveFileCommand:
def __init__(self, src, dest):
self.src = src
self.dest = dest
def execute(self):
self.rename(self.src, self.dest)
def undo(self):
self.rename(self.dest, self.src)
def rename(self, src, dest):
os.rename(src, dest)
iterator
iterator: 迭代器
def count_to(count):
numbers = ['one', 'two', 'three', 'four', 'five']
for number in numbers[:count]:
yield number
count_to_two = lambda: count_to(2)
count_to_five = lambda: count_to(5)
def main():
for number in count_to_two():
print(number)
mediator
mediator: 中间人
class ChatRoom:
def display_message(self, user, message):
print("[{} says]: {}".format(user, message))
class User:
def __init__(self, name):
self.name = name
self.chat_room = ChatRoom()
def say(self, message):
self.chat_room.display_message(self, message)
def __str__(self):
return self.name
def main():
molly = User('Molly')
molly.say("Hi Wcg")
"""[molly says]: Hi Wcg"""
memento
memento: 纪念, 生成不透明的令牌,可用于返回先前的状态
observer
observer: 观察者模式,提供回调以通知事件/数据更改
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self, modifier=None):
for observer in self._observers:
if modifier != observer:
observer.update(self)
class Data(Subject):
def __init__(self, name=''):
Subject.__init__(self)
self.name = name
self._data = 0
@property
def data(self):
return self._data
@data.setattr
def data(self, value):
self._data = value
self.notify()
class HexViewer:
def update(self, subject):
print('HexViewer: Subject %s has data 0x%x' % (subject.name, subject.data))
class DecimalViewer:
def update(self, subject):
print('DecimalViewer: Subject %s has data %d' % (subject.name, subject.data))
publish_subscribe
iterator: 发布/订阅
class Provider:
def __init__(self):
self.msg_queue = []
self.subscribes = {}
def notify(self, msg):
self.msg_queue.append(msg)
def subscribe(self, msg, subscriber):
self.subscribes.setdefault(msg, []).append(subscriber)
def unsubscribe(self, msg, subscriber):
self.subscribes[msg].remove(subscriber)
def update(self):
for msg in self.msg_queue:
for sub in self.subscribes.get(msg, []):
sub.run(msg)
self.msg_queue = []
class Publisher:
"""发布"""
def __init__(self, msg_center):
self.provider = msg_center
def publish(self, msg):
self.provider.notify(msg)
class Subscriber:
"""订阅"""
def __init__(self, name, msg_center):
self.name = name
self.provider = msg_center
def subscribe(self, msg):
self.provider.subscribe(msg, self)
def unsubscribe(self, msg):
self.provider.unsubscribe(msg, self)
def run(self, msg):
print("{} got {}".format(self.name, msg))
def main():
message_center = Provider()
fftv = Publisher(message_center)
jim = Subscriber("jim", message_center)
jim.subscribe("cartoon")
jack = Subscriber("jack", message_center)
jack.subscribe("music")
fftv.publish("cartoon")
fftv.publish("music")
message_center.update()
"""jim got cartoon
jack got music"""
iterator
iterator: 迭代器
参考
https://github.com/faif/python-patterns
https://python-web-guide.readthedocs.io/zh/latest/design/design.html
https://github.com/itswcg/Books/blob/master/Head%20First%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.pdf>