Skip to content

Commit

Permalink
完善部分模式描述及代码
Browse files Browse the repository at this point in the history
  • Loading branch information
wklken committed Jun 18, 2017
1 parent 623db55 commit 017401b
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 27 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ py-patterns
#### 3. 行为型

- 观察者 [observer](https://github.com/wklken/py-patterns/blob/master/observer.py)
- 模板方法 [abstract](https://github.com/wklken/py-patterns/blob/master/abstract.py)
- 模板方法 [abstract](https://github.com/wklken/py-patterns/blob/master/template_method.py)
- 命令 [command](https://github.com/wklken/py-patterns/blob/master/command.py)
- 状态 [state](https://github.com/wklken/py-patterns/blob/master/state.py)
- 责任链 [chain_of_responsibility](https://github.com/wklken/py-patterns/blob/master/chain_of_responsibility.py)
Expand All @@ -44,11 +44,12 @@ py-patterns
### 参考

- 大话设计模式
- 图解设计模式
- [python-patterns](https://github.com/faif/python-patterns)

### TODO:

review with https://github.com/faif/python-patterns
- review with https://github.com/faif/python-patterns


# Donation
Expand Down
39 changes: 28 additions & 11 deletions adapter.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
#!/usr/bin/env python
# encoding: utf-8
"""
适配器模式
适配器模式,也称为wrapper模式, 包装的意思
将一个类的接口转换成客户希望的另一个接口.
使得原本由于接口不兼容而不能work的那些类可以work
使得原本由于接口不兼容而不能work的那些类可以work. 用于填补'现有功能'和'所需功能'之间差异
- 适用: 系统的数据和行为都正确, 但是接口不符时. (已存在, 但是其接口和需要的不同)
- 适用: 当前现有的已经被充分测试, 并且已经被其他很多系统调用, 此时不宜修改, 但是又必须加入新功能用于满足某些需求
- 主要用于, 希望复用一些现存的类, 但接口又与复用环境要求不一致的情况
- 客户代码可以统一调用同一接口, 简单直接紧凑
- 可以再完全不改变现有代码的前提下, 使现有代码适配于新的接口
比喻:
- 笔记本使用的是12V, 而外部电源有100-220v 不同的, 此时需要一个电源适配器, 对电源进行适配
实现:
- 类适配模式(使用继承)
- 对象适配模式(使用委托)
在重构中的应用:
调用了第三方系统, 例如redis/elasticsearch/requests库等, 都有自己独立的库,
但是, 基本封装并不足以满足现有的业务需求
此时, 可以封装一个 XXClient, 将原来接口再封装, 实现依赖相关的业务逻辑
最终, 外部系统只需要调用 XXClient 即可, 业务逻辑都被封装(也有点facade模式的意思)
"""

# 基于继承的

from abc import ABCMeta, abstractmethod


class Adaptee(object):
"""
需要适配的类, 需要被被适配的
"""

def special_request(self):
print "I am special"


class Target(object):
"""
客户锁期待的接口, 目标可以使具体或抽象的类, 也可以是接口
Expand All @@ -25,15 +51,6 @@ def request(self):
pass


class Adaptee(object):
"""
需要适配的类
"""

def special_request(self):
print "I am special"


class Adapter(Target):
"""
适配器, 通过在内部包装一个adapter对象, 把源接口转换成目标接口
Expand Down
17 changes: 17 additions & 0 deletions builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
- 用户只需指定需要建造的类型, 不需要知道具体地建造过程和细节
- 建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式
- 可替换性
举例:
一篇文章, 存在很多结构, 例如title/author/content/create_time等, 系统输出时, 要分两种方式展现
text和html, 输出每一部分的实现都不一样, 此时, 上层不需要知道底层两个输出格式是如何实现的
"""

from abc import ABCMeta, abstractmethod
Expand Down Expand Up @@ -48,6 +54,9 @@ def get_result(self):


class BuilderA(Builder):
"""
具体建造者A
"""
def __init__(self):
self.__product = Product()

Expand All @@ -62,6 +71,9 @@ def get_result(self):


class BuilderB(Builder):
"""
具体建造者B
"""
def __init__(self):
self.__product = Product()

Expand All @@ -76,6 +88,11 @@ def get_result(self):


class Director(object):
"""
指挥构建过程
director不知道自己用的是哪个, 即: 只有不知道, 才能随时替换
"""
@staticmethod
def construct(builder):
builder.build_part_1()
Expand Down
51 changes: 45 additions & 6 deletions iterator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
- 无差别遍历聚合对象
- 需要对聚集进行多种方式遍历时
- 分离了集合对象的遍历行为, 做到不暴露集合内部结构, 又可以让外部代码透明的访问集合内部的数据
用于在数据集合中按照顺序遍历集合, 让用户通过特定的接口巡访容器中的每一个元素而不用了解底层的实现
wiki: https://zh.wikipedia.org/wiki/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F
python:
- http://nvie.com/posts/iterators-vs-generators/
- https://docs.python.org/2/glossary.html#term-iterator
- https://docs.python.org/2/library/collections.html#collections.Iterable
- https://docs.python.org/2/library/collections.html#collections.Iterator
"""

# 不考虑默认的迭代器

from abc import ABCMeta, abstractmethod


Expand All @@ -29,10 +36,16 @@ def first(self):

@abstractmethod
def next(self):
"""
object
"""
pass

@abstractmethod
def is_done(self):
def has_next(self):
"""
bool
"""
pass

@abstractmethod
Expand All @@ -55,13 +68,37 @@ def next(self):
result = self.__aggregate[self.current]
return result

def is_done(self):
def has_next(self):
return self.current >= len(self.__aggregate)

def current_item(self):
return self.__aggregate[self.current]


# python 定义一个迭代器
import collections # noqa


class YRange(collections.Iterator):
def __init__(self, n):
self.i = 0
self.n = n

def __iter__(self):
return self

def has_next(self):
return self.i < self.n

def next(self):
if self.i < self.n:
i = self.i
self.i += 1
return i
else:
raise StopIteration()


if __name__ == '__main__':
aggregate = [0] * 3

Expand All @@ -71,10 +108,12 @@ def current_item(self):

it = ConcreteIterator(aggregate)
i = it.first()
while not it.is_done():
while not it.has_next():
print "current:", it.current_item()
it.next()

y = YRange(3)
print list(y)



y1 = YRange(5)
print iter(y1)
34 changes: 33 additions & 1 deletion prototype.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
- 原型模型其实是从一个对象再创建另外一个可定制的对象, 而且不需要知道任何创建细节
- 一般在初始化信息不发生变化的情况下, 克隆是最好的办法, 既隐藏了对象创建的细节, 有提高了性能
在不指定类名的前提下生成实例
- 对象种类繁多, 无法将它们整合到一个类中
- 难以根据类生成实例时
- 解耦框架与生成实例: 让框架不依赖于具体的类, 不能指定类名来生成实例, 要实现注册一个原型
然后, 通过复制该实例来生成新的实例
why: 一旦在代码中出现要使用的类的名字, 就无法与该类分离开来, 也就无法实现复用
示例:
"""
import copy
from abc import ABCMeta, abstractmethod
Expand Down Expand Up @@ -39,7 +50,7 @@ class ConcretePrototypeA(Prototype):
具体原型类, 实现一个克隆自身的操作
"""
def clone(self):
# 浅拷贝
# 浅拷贝, 注意
return copy.copy(self)


Expand All @@ -51,9 +62,30 @@ def clone(self):
return copy.copy(self)


class Manager(object):
def __init__(self):
self._dict = {}

def register(self, name, prototype):
self._dict[name] = prototype

def create(self, proto_name):
p = self._dict.get(proto_name)
return p.clone()


if __name__ == '__main__':
ca = ConcretePrototypeA(1)
c2 = ca.clone()
print c2.id

# with manager
cb = ConcretePrototypeB(2)

m = Manager()
m.register("ca", ca)
m.register("cb", cb)

x = m.create("cb")
print x.id

14 changes: 10 additions & 4 deletions singleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
保证一个类仅有一个实例, 并提供一个访问他的全局访问点
TODO: 如果是多线程, 要考虑加锁
- 确保任何情况下绝对只有一个实例
坑:
- 多进程, 要考虑加锁
- web时, 往往是多进程起
- web时, 扩容时还往往是多机器多实例
"""


Expand All @@ -14,15 +20,15 @@ class Singleton(type):

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **
kwargs)
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]


#Python2
# Python2
class MyClass(object):
__metaclass__ = Singleton


if __name__ == '__main__':
a = MyClass()
b = MyClass()
Expand Down
12 changes: 9 additions & 3 deletions abstract.py → template_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
"""
模板方法模式
定义一个操作中的算法的股价, 而将一些步骤的实现延迟到子类中
这样, 可以使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
定义一个操作中的算法的构架, 而将一些步骤的实现延迟到子类中
这样, 可以使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤(相当于, 只需要覆写某些方法)
- 在父类中定义处理流程的框架, 在子类中实现具体处理的模式
- 在抽象类阶段确定处理的流程
- 使用继承改变程序的行为
- 把不变行为放到超类, 去除子类中的重复代码
- 提供了一个很好地代码复用平台
注意: 在子类中实现父类中声明的抽象方法时, 必须要理解这些抽象方法被调用的时机
"""

from abc import ABCMeta, abstractmethod


class AbstractClass(object):
"""
实现了一个模板方法, 定义了算法的挂架
Expand Down Expand Up @@ -48,4 +55,3 @@ def world(self):
if __name__ == '__main__':
c = ConcreteClass()
c.say_hello()

0 comments on commit 017401b

Please sign in to comment.