Skip to content

Commit 249a527

Browse files
committedOct 8, 2019
no message
1 parent 19ccd45 commit 249a527

15 files changed

+1004
-0
lines changed
 

‎monkey_print2.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/5/9 19:02
4+
"""
5+
不直接给print打补丁,自己重新赋值。
6+
7+
"""
8+
import sys
9+
import time
10+
11+
12+
# noinspection PyProtectedMember,PyUnusedLocal,PyIncorrectDocstring
13+
def nb_print(*args, sep=' ', end='\n', file=None):
14+
"""
15+
超流弊的print补丁
16+
:param x:
17+
:return:
18+
"""
19+
# 获取被调用函数在被调用时所处代码行数
20+
line = sys._getframe().f_back.f_lineno
21+
# 获取被调用函数所在模块文件名
22+
file_name = sys._getframe(1).f_code.co_filename
23+
# sys.stdout.write(f'"{__file__}:{sys._getframe().f_lineno}" {x}\n')
24+
args = (str(arg) for arg in args) # REMIND 防止是数字不能被join
25+
sys.stdout.write(f'"{file_name}:{line}" {time.strftime("%H:%M:%S")} \033[0;94m{"".join(args)}\033[0m\n') # 36 93 96 94
26+
27+
28+
print = nb_print # 这是打猴子补丁。
29+
30+
if __name__ == '__main__':
31+
print(0)
32+
nb_print(123, 'abc')
33+
print = nb_print
34+
print(456, 'def')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
享元模式
6+
享元模式通过为相似对象引入数据共享来最小化内存使用,提升性能,一个享元就是一个包含状态的独立的不可变数据的共享对象,依赖状态的可变数据不应是享元的一部分,因为每个对象的这种信息不相同,无法共享,如果享元需要非固有数据应该由客户端代码显示提供。
7+
8+
享元模式介于单例模式和不加控制得多例模式之间。非常灵活,实用性和使用场景大于单例模式。
9+
例如创建一个数据库连接,不希望建立多个连接,但又要在同一解释器下操作好多台机器的数据库,当传参的机器的ip端口不同时候,那肯定要创建一个新的连接了,这种使用享元模式适合。
10+
"""
11+
from functools import wraps
12+
13+
from monkey_print2 import print
14+
15+
16+
def flyweight(cls):
17+
_instance = {}
18+
19+
def _make_arguments_to_key(args, kwds):
20+
key = args
21+
if kwds:
22+
sorted_items = sorted(kwds.items())
23+
for item in sorted_items:
24+
key += item
25+
return key
26+
27+
@wraps(cls)
28+
def _flyweight(*args, **kwargs):
29+
cache_key = f'{cls}_{_make_arguments_to_key(args, kwargs)}'
30+
if cache_key not in _instance:
31+
_instance[cache_key] = cls(*args, **kwargs)
32+
return _instance[cache_key]
33+
34+
return _flyweight
35+
36+
37+
@flyweight
38+
class A:
39+
def __init__(self, identity):
40+
self.identity = identity
41+
42+
def eat(self):
43+
print(f'{self.identity} 吃饭')
44+
45+
46+
if __name__ == '__main__':
47+
a1 = A('001')
48+
a2 = A('001')
49+
print(a1 == a2)
50+
a1.eat()
51+
a2.eat()
52+
a3 = A('003')
53+
print(a1 == a3)
54+
a3.eat()
55+
56+
"""
57+
a1和a2是同一个对象,
58+
"D:/coding2/python36patterns/创建型模式-享元模式-装饰器版本.py:49" 15:48:38 True
59+
"D:/coding2/python36patterns/创建型模式-享元模式-装饰器版本.py:43" 15:48:38 001 吃饭
60+
"D:/coding2/python36patterns/创建型模式-享元模式-装饰器版本.py:43" 15:48:38 001 吃饭
61+
"D:/coding2/python36patterns/创建型模式-享元模式-装饰器版本.py:53" 15:48:38 False
62+
"D:/coding2/python36patterns/创建型模式-享元模式-装饰器版本.py:43" 15:48:38 003 吃饭
63+
"""

‎创建型模式-享元模式.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
享元模式
6+
享元模式通过为相似对象引入数据共享来最小化内存使用,提升性能,一个享元就是一个包含状态的独立的不可变数据的共享对象,依赖状态的可变数据不应是享元的一部分,因为每个对象的这种信息不相同,无法共享,如果享元需要非固有数据应该由客户端代码显示提供。
7+
8+
享元模式介于单例模式和不加控制得多例模式之间。非常灵活,实用性和使用场景大于单例模式。
9+
例如创建一个数据库连接,不希望建立多个连接,但又要在同一解释器下操作好多台机器的数据库,当传参的机器的ip端口不同时候,那肯定要创建一个新的连接了,这种使用享元模式适合。
10+
"""
11+
from monkey_print2 import print
12+
13+
14+
class A:
15+
pool = dict()
16+
17+
def __new__(cls, identity):
18+
"""
19+
假设相同的学号只会有1个学生
20+
:param identity:
21+
:return:
22+
"""
23+
obj = cls.pool.get(identity, None)
24+
if not obj:
25+
obj = object.__new__(cls)
26+
print(f'实例化 学号为 {identity} 的学生')
27+
cls.pool[identity] = obj
28+
return obj
29+
30+
def __init__(self, identity):
31+
self.identity = identity
32+
33+
def eat(self):
34+
print(f'{self.identity} 吃饭')
35+
36+
if __name__ == '__main__':
37+
A('001').eat()
38+
A('001').eat()
39+
A('002').eat()
40+
41+
"""
42+
不会多次生成 001学号的同学这个对象。
43+
"D:/coding2/python36patterns/创建型模式-享元模式.py:17" 15:29:38 实例化 学号为 001 的学生
44+
"D:/coding2/python36patterns/创建型模式-享元模式.py:25" 15:29:38 001 吃饭
45+
"D:/coding2/python36patterns/创建型模式-享元模式.py:25" 15:29:38 001 吃饭
46+
"D:/coding2/python36patterns/创建型模式-享元模式.py:17" 15:29:38 实例化 学号为 002 的学生
47+
"D:/coding2/python36patterns/创建型模式-享元模式.py:25" 15:29:38 002 吃饭
48+
"""
49+
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
单例模式
6+
适用范围三颗星,这不是最常用的设计模式。往往只能脱出而出仅仅能说出这一种设计模式,但oop根本目的是要多例,
7+
使用oop来实现单例模式,好处包括
8+
1 延迟初始化(只有在生成对象时候调用__init__里面时候才进行初始化)
9+
2 动态传参初始化
10+
否则,一般情况下,不需要来使用类来搞单例模式,文件级模块全局变量的写法搞定即可,python模块天然单例,不信的话可以测试一下,c导入a,b也导入a,c导入b,在a里面直接print hello,
11+
运行c.py,只会看到一次print hello。
12+
13+
"""
14+
import threading
15+
from functools import wraps
16+
17+
from monkey_print2 import print
18+
19+
20+
class Singleton(type):
21+
def __init__(cls, name, bases, dict):
22+
super(Singleton, cls).__init__(name, bases, dict)
23+
cls.instance = None
24+
25+
def __call__(cls, *args, **kw):
26+
if cls.instance is None:
27+
cls.instance = super(Singleton, cls).__call__(*args, **kw)
28+
return cls.instance
29+
30+
31+
class A(metaclass=Singleton):
32+
def __init__(self, identity):
33+
print('执行init')
34+
self.identity = identity
35+
36+
def eat(self):
37+
print(f'{self.identity} 吃饭')
38+
39+
40+
if __name__ == '__main__':
41+
a1 = A('001')
42+
a2 = A('001')
43+
print(a1 == a2)
44+
a1.eat()
45+
a2.eat()
46+
a3 = A('003')
47+
print(a1 == a3)
48+
a3.eat()
49+
50+
"""
51+
a1 a2 a3 三次实例化出来,但都是同一个对象。对比下享元模式。
52+
"D:/coding2/python36patterns/创建型模式-单例模式.py:36" 16:00:25 True
53+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 001 吃饭
54+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 001 吃饭
55+
"D:/coding2/python36patterns/创建型模式-单例模式.py:40" 16:00:25 True
56+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 003 吃饭
57+
"""
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
单例模式
6+
适用范围三颗星,这不是最常用的设计模式。往往只能脱出而出仅仅能说出这一种设计模式,但oop根本目的是要多例,
7+
使用oop来实现单例模式,好处包括
8+
1 延迟初始化(只有在生成对象时候调用__init__里面时候才进行初始化)
9+
2 动态传参初始化
10+
否则,一般情况下,不需要来使用类来搞单例模式,文件级模块全局变量的写法搞定即可,python模块天然单例,不信的话可以测试一下,c导入a,b也导入a,c导入b,在a里面直接print hello,
11+
运行c.py,只会看到一次print hello。
12+
13+
"""
14+
import threading
15+
from functools import wraps
16+
17+
from monkey_print2 import print
18+
19+
20+
def singleton(cls):
21+
"""
22+
单例模式装饰器,新加入线程锁,更牢固的单例模式,主要解决多线程如100线程同时实例化情况下可能会出现三例四例的情况,实测。
23+
"""
24+
_instance = {}
25+
singleton.__lock = threading.Lock() # 这里直接演示了线程安全版单例模式
26+
27+
@wraps(cls)
28+
def _singleton(*args, **kwargs):
29+
with singleton.__lock:
30+
if cls not in _instance:
31+
_instance[cls] = cls(*args, **kwargs)
32+
return _instance[cls]
33+
34+
return _singleton
35+
36+
37+
@singleton
38+
class A:
39+
def __init__(self, identity):
40+
self.identity = identity
41+
42+
def eat(self):
43+
print(f'{self.identity} 吃饭')
44+
45+
46+
if __name__ == '__main__':
47+
a1 = A('001')
48+
a2 = A('001')
49+
print(a1 == a2)
50+
a1.eat()
51+
a2.eat()
52+
a3 = A('003')
53+
print(a1 == a3)
54+
a3.eat()
55+
56+
"""
57+
a1 a2 a3 三次实例化出来,但都是同一个对象。对比下享元模式。
58+
"D:/coding2/python36patterns/创建型模式-单例模式.py:36" 16:00:25 True
59+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 001 吃饭
60+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 001 吃饭
61+
"D:/coding2/python36patterns/创建型模式-单例模式.py:40" 16:00:25 True
62+
"D:/coding2/python36patterns/创建型模式-单例模式.py:30" 16:00:25 003 吃饭
63+
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
单例模式
6+
适用范围三颗星,这不是最常用的设计模式。往往只能脱出而出仅仅能说出这一种设计模式,但oop根本目的是要多例,
7+
使用oop来实现单例模式,好处包括
8+
1 延迟初始化(只有在生成对象时候调用__init__里面时候才进行初始化)
9+
2 动态传参初始化
10+
否则,一般情况下,不需要来使用类来搞单例模式,文件级模块全局变量的写法搞定即可,python模块天然单例,不信的话可以测试一下,c导入a,b也导入a,c导入b,在a里面直接print hello,
11+
运行c.py,只会看到一次print hello。
12+
13+
"""
14+
15+
16+
from monkey_print2 import print
17+
18+
19+
class A:
20+
"""
21+
# &&&&&这种方式重写new实现的单例模式要注意,虽然生成的对象都是同一个,但init会每次都被自动调用。py2这种写法实现的单例模式,init不会自动被调用,py3会被自动调用。
22+
要是init里面成本很大,不希望被自动调用,可以改成另外的方式,参考其他方式的单例模式。&&&&&
23+
修改上面这个缺点的重写new方式
24+
"""
25+
_inst = None
26+
def __new__(cls, *args,**kwargs):
27+
if not cls._inst:
28+
cls._inst = object.__new__(cls)
29+
cls._inst.__custom_init__(*args,**kwargs) # 重点在这里。
30+
return cls._inst
31+
32+
def __custom_init__(self, identity): # 这行也是是重点。去掉了__init__方法,init会被自动调用,改成在new里面主动调用。
33+
print('执行init')
34+
self.identity = identity
35+
36+
def eat(self):
37+
print(f'{self.identity} 吃饭')
38+
39+
40+
if __name__ == '__main__':
41+
a1 = A('001')
42+
a2 = A('001')
43+
print(a1 == a2)
44+
a1.eat()
45+
a2.eat()
46+
a3 = A('003')
47+
print(a1 == a3)
48+
a3.eat()
49+
50+
"""
51+
init只会执行一次。
52+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:33" 16:20:19 执行init
53+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:43" 16:20:19 True
54+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:37" 16:20:19 001 吃饭
55+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:37" 16:20:19 001 吃饭
56+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:47" 16:20:19 True
57+
"D:/coding2/python36patterns/创建型模式-单例模式-重写new但不每次执行init方式.py:37" 16:20:19 001 吃饭
58+
59+
60+
"""

‎创建型模式-单例模式.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
单例模式
6+
适用范围三颗星,这不是最常用的设计模式。往往只能脱出而出仅仅能说出这一种设计模式,但oop根本目的是要多例,
7+
使用oop来实现单例模式,好处包括
8+
1 延迟初始化(只有在生成对象时候调用__init__里面时候才进行初始化)
9+
2 动态传参初始化
10+
否则,一般情况下,不需要来使用类来搞单例模式,文件级模块全局变量的写法搞定即可,python模块天然单例,不信的话可以测试一下,c导入a,b也导入a,c导入b,在a里面直接print hello,
11+
运行c.py,只会看到一次print hello。
12+
13+
"""
14+
15+
16+
from monkey_print2 import print
17+
18+
19+
class A:
20+
"""
21+
# 这种方式重写new实现的单例模式要注意,虽然生成的对象都是同一个,但init会每次都被自动调用。py2这种写法实现的单例模式,init不会自动被调用,py3会被自动调用。
22+
要是init里面成本很大,不希望每次都被自动调用,可以改成另外的方式,参考其他方式的单例模式。
23+
"""
24+
_inst = None
25+
def __new__(cls, identity):
26+
if not cls._inst:
27+
cls._inst = object.__new__(cls)
28+
return cls._inst
29+
30+
def __init__(self, identity):
31+
print('执行init')
32+
self.identity = identity
33+
34+
def eat(self):
35+
print(f'{self.identity} 吃饭')
36+
37+
38+
if __name__ == '__main__':
39+
a1 = A('001')
40+
a2 = A('001')
41+
print(a1 == a2)
42+
a1.eat()
43+
a2.eat()
44+
a3 = A('003')
45+
print(a1 == a3)
46+
a3.eat()
47+
48+
"""
49+
"D:/coding2/python36patterns/创建型模式-单例模式.py:27" 16:13:31 执行init
50+
"D:/coding2/python36patterns/创建型模式-单例模式.py:27" 16:13:31 执行init
51+
"D:/coding2/python36patterns/创建型模式-单例模式.py:37" 16:13:31 True
52+
"D:/coding2/python36patterns/创建型模式-单例模式.py:31" 16:13:31 001 吃饭
53+
"D:/coding2/python36patterns/创建型模式-单例模式.py:31" 16:13:31 001 吃饭
54+
"D:/coding2/python36patterns/创建型模式-单例模式.py:27" 16:13:31 执行init
55+
"D:/coding2/python36patterns/创建型模式-单例模式.py:41" 16:13:31 True
56+
"D:/coding2/python36patterns/创建型模式-单例模式.py:31" 16:13:31 003 吃饭
57+
58+
"""

‎创建型模式-原型模式.py

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
原型模式
6+
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
7+
8+
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
9+
10+
介绍
11+
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
12+
13+
主要解决:在运行期建立和删除原型。
14+
15+
何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
16+
17+
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。
18+
19+
关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。
20+
21+
应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。
22+
23+
优点: 1、性能提高。 2、逃避构造函数的约束。
24+
25+
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
26+
27+
使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
28+
29+
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
30+
"""
31+
from monkey_print2 import print
32+
33+
import copy
34+
from collections import OrderedDict
35+
36+
37+
class Book:
38+
def __init__(self, name, authors, price, **rest):
39+
'''rest的例子有:出版商、长度、标签、出版日期'''
40+
self.name = name
41+
self.authors = authors
42+
self.price = price
43+
self.__dict__.update(rest) # 添加其他额外属性
44+
45+
def __str__(self):
46+
mylist = []
47+
ordered = OrderedDict(sorted(self.__dict__.items()))
48+
for i in ordered.keys():
49+
mylist.append('{}: {}'.format(i, ordered[i]))
50+
if i == 'price':
51+
mylist.append('$')
52+
mylist.append('\n')
53+
return ''.join(mylist)
54+
55+
56+
class Prototype:
57+
def __init__(self):
58+
self.objects = dict() # 初始化一个原型列表
59+
60+
def register(self, identifier, obj):
61+
# 在原型列表中注册原型对象
62+
self.objects[identifier] = obj
63+
64+
def unregister(self, identifier):
65+
# 从原型列表中删除原型对象
66+
del self.objects[identifier]
67+
68+
def clone(self, identifier, **attr):
69+
# 根据 identifier 在原型列表中查找原型对象并克隆
70+
found = self.objects.get(identifier)
71+
if not found:
72+
raise ValueError('Incorrect object identifier: {}'.format(identifier))
73+
obj = copy.deepcopy(found)
74+
obj.__dict__.update(attr) # 用新的属性值替换原型对象中的对应属性
75+
return obj
76+
77+
78+
79+
80+
if __name__ == '__main__':
81+
b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
82+
price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
83+
tags=('C', 'programming', 'algorithms', 'data structures'))
84+
85+
prototype = Prototype()
86+
cid = 'k&r-first'
87+
prototype.register(cid, b1)
88+
b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274, publication_date='1988-04-01', edition=2)
89+
90+
for i in (b1, b2):
91+
print(i)
92+
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))

‎创建型模式-对象池模式.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 16:41
4+
"""
5+
重要的模式之一。使用这种模式可以创造数据库连接池 浏览器池等。
6+
实现原理有两个重要的地方是,使用时候借,使用完成后归还。我使用这个创造了一个非常强大的场景。
7+
最好是使用with语法来完成对象的借和还,减少调用处的代码。
8+
9+
资源受限的, 不需要可伸缩性的环境(cpu\内存等物理资源有限): cpu性能不够强劲, 内存比较紧张, 垃圾收集, 内存抖动会造成比较大的影响, 需要提高内存管理效率, 响应性比吞吐量更为重要;
10+
数量受限的, 比如数据库连接;
11+
创建成本高的对象, 可以考虑是否池化, 比较常见的有线程池(ThreadPoolExecutor), 字节数组池等。
12+
"""
13+
from queue import Queue
14+
from monkey_print2 import print
15+
16+
17+
class QueueObject():
18+
19+
def __init__(self, queue, auto_get=False):
20+
self._queue = queue
21+
self.object = self._queue.get() if auto_get else None
22+
23+
def __enter__(self):
24+
if self.object is None:
25+
self.object = self._queue.get()
26+
return self.object
27+
28+
def __exit__(self, Type, value, traceback):
29+
if self.object is not None:
30+
self._queue.put(self.object)
31+
self.object = None
32+
33+
def __del__(self):
34+
if self.object is not None:
35+
self._queue.put(self.object)
36+
self.object = None
37+
38+
39+
def main():
40+
sample_queue = Queue()
41+
sample_queue.put('yam')
42+
with QueueObject(sample_queue) as obj:
43+
print('Inside with: {}'.format(obj))
44+
print('Outside with: {}'.format(sample_queue.get()))
45+
46+
sample_queue.put('sam')
47+
queue_object = QueueObject(sample_queue, True)
48+
print('内部 func: {}'.format(queue_object.object))
49+
print('外部 func: {}'.format(sample_queue.get()))
50+
51+
if not sample_queue.empty():
52+
print(sample_queue.get())
53+
54+
55+
if __name__ == '__main__':
56+
main()

‎创建型模式-建造者模式.py

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
建造者模式
6+
7+
建造者模式
8+
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
9+
10+
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
11+
12+
介绍
13+
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
14+
15+
主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
16+
17+
何时使用:一些基本部件不会变,而其组合经常变化的时候。
18+
19+
如何解决:将变与不变分离开。
20+
21+
关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
22+
23+
应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。
24+
25+
优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
26+
27+
缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
28+
29+
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。
30+
31+
注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
32+
"""
33+
from monkey_print2 import print
34+
35+
import abc
36+
37+
38+
# 步骤一:创建对应的产品抽象类/产品类
39+
class Building(object):
40+
def __init__(self):
41+
self.floor = None
42+
self.size = None
43+
44+
def __repr__(self):
45+
return 'Floor: {0.floor} | size: {0.size}'.format(self)
46+
47+
48+
# 步骤三:创建构建者抽象类,主要是定义构建者通用属性/方法,以及继承者必须实现的功能抽象
49+
# Abstract builder
50+
class AbsBuilder(object):
51+
def __init__(self):
52+
self.building = None
53+
54+
def new_building(self):
55+
self.building = Building()
56+
57+
@abc.abstractmethod
58+
def build_floor(self):
59+
pass
60+
61+
@abc.abstractmethod
62+
def build_size(self):
63+
pass
64+
65+
66+
# 步骤四:具体构建者类实现
67+
class HouseBuilder(AbsBuilder):
68+
def build_floor(self):
69+
self.building.floor = 'one'
70+
71+
def build_size(self):
72+
self.building.size = '220 squre'
73+
74+
75+
class FlatBuilder(AbsBuilder):
76+
def build_floor(self):
77+
self.building.floor = 'seven'
78+
79+
def build_size(self):
80+
self.building.size = '140 squre'
81+
82+
83+
# 步骤二:创建产品的指挥者类,即最终提供给客户端的产品的实例对象,以及组装过程
84+
class Director(object):
85+
def __init__(self):
86+
self.builder = None
87+
88+
def construct_building(self):
89+
"""
90+
#建造者模式下,仅在需要时客户端代码才显式地请求指挥者返回最终的对象
91+
"""
92+
self.builder.new_building()
93+
self.builder.build_floor()
94+
self.builder.build_size()
95+
96+
def get_building(self):
97+
return self.builder.building
98+
99+
100+
class Client(object):
101+
def build(self, build_type):
102+
if build_type == "House":
103+
director = Director()
104+
builder = HouseBuilder()
105+
director.builder = builder
106+
director.construct_building()
107+
building = director.get_building()
108+
print(building)
109+
else:
110+
director = Director()
111+
builder = FlatBuilder()
112+
director.builder = builder
113+
director.construct_building()
114+
building = director.get_building()
115+
print(building)
116+
117+
118+
if __name__ == "__main__":
119+
build_type = "Flat"
120+
client = Client()
121+
client.build(build_type)

‎创建型模式-抽象工厂模式.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
抽象工厂模式
6+
7+
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
8+
9+
抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。
10+
11+
根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。
12+
13+
换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
14+
"""
15+
from monkey_print2 import print
16+
17+
18+
class Xiaomi5:
19+
def __init__(self):
20+
self.phone_name = '小米5'
21+
22+
def send_msg(self):
23+
print(f'用 {self.phone_name} 发短信')
24+
25+
26+
class Xiaomi6:
27+
def __init__(self):
28+
self.phone_name = '小米6'
29+
30+
def send_msg(self):
31+
print(f'用 {self.phone_name} 发短信')
32+
33+
34+
class XiaomFactory:
35+
@staticmethod
36+
def get_phone(phone_type):
37+
if phone_type == '5':
38+
return Xiaomi5()
39+
elif phone_type == '6':
40+
return Xiaomi6()
41+
42+
43+
class Apple5:
44+
def __init__(self):
45+
self.phone_name = '苹果5'
46+
47+
def send_msg(self):
48+
print(f'用 {self.phone_name} 发短信')
49+
50+
51+
class Apple6:
52+
def __init__(self):
53+
self.phone_name = '苹果6'
54+
55+
def send_msg(self):
56+
print(f'用 {self.phone_name} 发短信')
57+
58+
59+
class AppleFactory:
60+
@staticmethod
61+
def get_phone(phone_type):
62+
if phone_type == '5':
63+
return Xiaomi5()
64+
elif phone_type == '6':
65+
return Xiaomi6()
66+
67+
68+
class FactoryProducer:
69+
@staticmethod
70+
def get_factory(factory_name):
71+
if factory_name == 'xiaomi':
72+
return XiaomFactory()
73+
elif factory_name == 'apple':
74+
return AppleFactory()
75+
76+
77+
if __name__ == '__main__':
78+
factory = FactoryProducer.get_factory('xiaomi')
79+
xiaomi5 = factory.get_phone('5')
80+
xiaomi5.send_msg()
81+
82+
"""
83+
"D:/coding2/python36patterns/创建型模式-抽象工厂模式.py:22" 14:38:03 用 小米5 发短信
84+
"""

‎创建型模式-简单工厂模式.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 13:55
4+
"""
5+
简单工厂模式
6+
7+
好处主要有:
8+
1、将创建实例的工作与使用实例的工作分开
9+
2、把初始化实例时的工作放到工厂里进行,使代码更容易维护。
10+
3、使得修改代码时不会引起太大的变动,良好的扩展性。
11+
比如,有对象A。现在要修改这个实例的方法。就会有对象B,继承A,然后重写A里面的某个方法。这时,如果没有工厂模式,那么就要把每次创建A对象的代码都改为创建B对象。这是很可怕的一件事情。
12+
如果有工厂模式,那么,我们可以只修改工厂中创建A对象的方法,就可以完成这件事情了。更容易的,可以把这个实例的创建写在配置文件中。那么对于这种变动,只要修改配置文件就可以实现了,不需要修改工厂类。
13+
"""
14+
from monkey_print2 import print
15+
16+
17+
class Xiaomi5:
18+
def __init__(self):
19+
self.phone_name = '小米5'
20+
21+
def send_msg(self):
22+
print(f'用 {self.phone_name} 发短信')
23+
24+
25+
class Xiaomi6:
26+
def __init__(self):
27+
self.phone_name = '小米6'
28+
29+
def send_msg(self):
30+
print(f'用 {self.phone_name} 发短信')
31+
32+
33+
def get_xiaomi_phone(phone_type):
34+
if phone_type == '5':
35+
return Xiaomi5()
36+
elif phone_type == '6':
37+
return Xiaomi6()
38+
39+
40+
if __name__ == '__main__':
41+
phone5 = get_xiaomi_phone('5')
42+
phone5.send_msg()
43+
44+
phone6 = get_xiaomi_phone('6')
45+
phone6.send_msg()
46+
47+
"""
48+
"D:/coding2/python36patterns/创建型模式-简单工厂模式.py:15" 14:16:27 用 小米5 发短信
49+
"D:/coding2/python36patterns/创建型模式-简单工厂模式.py:23" 14:16:27 用 小米6 发短信
50+
"""

‎结构型模式-桥接模式.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 17:39
4+
"""
5+
桥接,是像一座桥连接两岸,而Python程序设计中的桥接指的是抽象部分和实体部分的连接,简单来说是类和类实例化过称中的连接。
6+
7+
桥接模式通过在类和类实例化中间作用,使其抽象和实现可以独立变化而不互相干扰,这就是桥接模式最大的作用。
8+
9+
核心的思想是通过封装,将一个抽象类的相关参数和方法分别作为桥接类的属性,这样在实例化桥接类后通过修改桥接类的属性,便可以实现抽象和实现之间的独立变化。
10+
11+
"""
12+
from monkey_print2 import print
13+
14+
15+
class A:
16+
def run(self, name):
17+
print("my name is :{}".format(name))
18+
19+
20+
class B:
21+
def run(self, name):
22+
print("我的名字是:{}".format(name))
23+
24+
25+
class Bridge:
26+
def __init__(self, ager, classname):
27+
self.ager = ager
28+
self.classname = classname
29+
30+
def bridge_run(self):
31+
self.classname.run(self.ager)
32+
33+
34+
if __name__ == '__main__':
35+
test = Bridge('李华', A())
36+
test.bridge_run()
37+
test.ager = 'Tome'
38+
test.bridge_run()
39+
test.classname = B()
40+
test.bridge_run()
41+
test.ager = '李华'
42+
test.bridge_run()
43+
"""
44+
"D:/coding2/python36patterns/结构型模式-桥接模式.py:7" 17:56:50 my name is :李华
45+
"D:/coding2/python36patterns/结构型模式-桥接模式.py:7" 17:56:50 my name is :Tome
46+
"D:/coding2/python36patterns/结构型模式-桥接模式.py:12" 17:56:50 我的名字是:Tome
47+
"D:/coding2/python36patterns/结构型模式-桥接模式.py:12" 17:56:50 我的名字是:李华
48+
49+
"""

‎结构型模式-适配器模式.py

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 17:39
4+
"""
5+
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
6+
7+
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
8+
9+
"""
10+
from monkey_print2 import print
11+
12+
13+
class Dog:
14+
def __init__(self, name):
15+
self.name = name
16+
17+
def wangwang(self):
18+
print('my name is' + self.name + '。。。汪汪汪。。。')
19+
20+
def dog_run(self):
21+
print(f'{self.name} is running')
22+
23+
24+
class Cat:
25+
def __init__(self, name):
26+
self.name = name
27+
28+
def miaomiao(self):
29+
print('my name is' + self.name + '。。。喵喵喵。。。')
30+
31+
def cat_run(self):
32+
print(f'{self.name} is running')
33+
34+
35+
class Sheep:
36+
def __init__(self, name):
37+
self.name = name
38+
39+
def miemie(self):
40+
print('my name is' + self.name + '。。。咩咩。。。')
41+
42+
def sheet_run(self):
43+
print(f'{self.name} is running')
44+
45+
46+
class Adapter:
47+
def __init__(self, adapted_methods):
48+
49+
self.__dict__.update(adapted_methods)
50+
51+
def speak(self):
52+
pass
53+
54+
def run(self):
55+
pass
56+
57+
58+
def main():
59+
animals = []
60+
dog = Dog('旺财')
61+
cat = Cat('大脸猫')
62+
sheep = Sheep('喜洋洋')
63+
animals.append(Adapter({'speak': dog.wangwang, 'run': dog.dog_run}))
64+
animals.append(Adapter({'speak': cat.miaomiao, 'run': cat.cat_run}))
65+
animals.append(Adapter({'speak': sheep.miemie, 'run': sheep.sheet_run}))
66+
67+
for a in animals:
68+
a.speak()
69+
a.run()
70+
71+
72+
if __name__ == "__main__":
73+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
# @Time : 2019/10/8 0008 17:12
4+
"""
5+
23种设计模式中没有提到这一种。
6+
用于执行代价比较大的场景。可以选择永久缓存或者缓存一段时间。
7+
8+
"""
9+
import sys
10+
import time
11+
from functools import wraps
12+
13+
from monkey_print2 import print
14+
15+
class cached_class_property(object):
16+
"""类属性缓存装饰器,把方法的结果缓存为类属性"""
17+
18+
def __init__(self, func):
19+
self.func = func
20+
21+
def __get__(self, obj, cls):
22+
if obj is None:
23+
return self
24+
value = self.func(obj)
25+
setattr(cls, self.func.__name__, value)
26+
return value
27+
28+
29+
# noinspection PyPep8Naming
30+
class cached_instance_property(object):
31+
"""实例属性缓存装饰器,把方法的结果缓存为实例属性"""
32+
33+
def __init__(self, func):
34+
self.func = func
35+
36+
def __get__(self, obj, cls):
37+
print(obj, cls)
38+
if obj is None:
39+
return self
40+
value = obj.__dict__[self.func.__name__] = self.func(obj)
41+
return value
42+
43+
44+
45+
class FunctionResultCacher:
46+
"""
47+
使函数的结果缓存指定的时间。例如在5分钟内已经查询了深圳的天气,再次调用查天气的函数直接返回之前查询的天气。
48+
49+
"""
50+
func_result_dict = {}
51+
"""
52+
{
53+
(f1,(1,2,3,4)):(10,1532066199.739),
54+
(f2,(5,6,7,8)):(26,1532066211.645),
55+
}
56+
"""
57+
58+
@classmethod
59+
def cached_function_result_for_a_time(cls, cache_time: float):
60+
"""
61+
函数的结果缓存一段时间装饰器,不要装饰在返回结果是超大字符串或者其他占用大内存的数据结构上的函数上面。
62+
:param cache_time :缓存的时间
63+
:type cache_time : float
64+
"""
65+
66+
def _cached_function_result_for_a_time(fun):
67+
68+
@wraps(fun)
69+
def __cached_function_result_for_a_time(*args, **kwargs):
70+
# print(cls.func_result_dict)
71+
# if len(cls.func_result_dict) > 1024:
72+
if sys.getsizeof(cls.func_result_dict) > 100 * 1000 * 1000:
73+
cls.func_result_dict.clear()
74+
75+
key = cls._make_arguments_to_key(args, kwargs)
76+
if (fun, key) in cls.func_result_dict and time.time() - cls.func_result_dict[(fun, key)][1] < cache_time:
77+
return cls.func_result_dict[(fun, key)][0]
78+
else:
79+
print('函数 [{}] 此次不能使用缓存'.format(fun.__name__))
80+
result = fun(*args, **kwargs)
81+
cls.func_result_dict[(fun, key)] = (result, time.time())
82+
return result
83+
84+
return __cached_function_result_for_a_time
85+
86+
return _cached_function_result_for_a_time
87+
88+
@staticmethod
89+
def _make_arguments_to_key(args, kwds):
90+
key = args
91+
if kwds:
92+
sorted_items = sorted(kwds.items())
93+
for item in sorted_items:
94+
key += item
95+
return key # 元祖可以相加。

0 commit comments

Comments
 (0)
Please sign in to comment.