享元模式
Flyweight模式,顾名思义,就是共享元数据,在Python这个动态语言中可以提高程序性能和效率,比如从一个文件读取很多的字符串,而这些字符串必定重复,所以可以使用这个模式将其存在一个pool中
python的例子(我将提出一系列的例子不同方式实现这个功能)
普通青年版,看了Gof,可能就会有这样基础的一段代码:
class Spam(object):
def __init__(self, a, b):
self.a = a
self.b = b
class SpamFactory(object):
def __init__(self):
self.__instances = dict()
def get_instance(self, a, b):
if (a, b) not in self.__instances:
self.__instances[(a, b)] = Spam(a, b)
return self.__instances[(a, b)]
class Egg(object):
def __init__(self, x, y):
self.x = x
self.y = y
class EggFactory(object):
def __init__(self):
self.__instances = dict()
def get_instance(self, x, y):
if (x, y) not in self.__instances:
self.__instances[(x, y)] = Egg(x, y)
return self.__instances[(x, y)]
spamFactory = SpamFactory()
eggFactory = EggFactory()
assert spamFactory.get_instance(1, 2) is spamFactory.get_instance(1, 2)
assert eggFactory.get_instance('a', 'b') is eggFactory.get_instance('a', 'b')
assert spamFactory.get_instance(1, 2) is not eggFactory.get_instance(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
上面的是最简单能想到的,也是我见过用得最多的一种, 可是还有梦想青年版, 因为上面的东西是可以抽象出来的, 比如上面只能传入a,b2个,再多了就不行了,其他的风格也不行,比如我想缓存键值对,所以想起来了args和*kwargs
class FlyweightFactory(object):
def __init__(self, cls):
self._cls = cls
self._instances = dict()
def get_instance(self, *args, **kargs):
return self._instances.setdefault(
(args, tuple(kargs.items())),
self._cls(*args, **kargs))
class Spam(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
class Egg(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
SpamFactory = FlyweightFactory(Spam)
EggFactory = FlyweightFactory(Egg)
assert SpamFactory.get_instance(1, 2, 3) is SpamFactory.get_instance(1, 2, 3)
assert EggFactory.get_instance('a', 'b', 'c') is EggFactory.get_instance('a', 'b', 'c')
assert SpamFactory.get_instance(1, 2, 3) is not EggFactory.get_instance(1, 2, 3)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
然后就是我最喜欢的风格,装饰器解决这个问题,算是老土的文艺青年吧
class flyweight(object):
def __init__(self, cls):
self._cls = cls
self._instances = dict()
def __call__(self, *args, **kargs):
return self._instances.setdefault(
(args, tuple(kargs.items())),
self._cls(*args, **kargs))
@flyweight
class Spam(object):
def __init__(self, a, b):
self.a = a
self.b = b
@flyweight
class Egg(object):
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
但是我们实在态out了,首先,没必要把装饰器搞成一个类,完全可以使用函数式编程
def flyweight(cls):
instances = dict()
return lambda *args, **kargs: instances.setdefault(
(args, tuple(kargs.items())),
cls(*args, **kargs))
@flyweight
class Spam(object):
def __init__(self, a, b):
self.a = a
self.b = b
@flyweight
class Egg(object):
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
该是刚进城的文艺小青版版了,这里用了一个东西Mixin: 给某个具体的类一些它需要的具体功能
class FlyweightMixin(object):
_instances = dict()
@classmethod
def get_instance(cls, *args, **kargs):
return cls._instances.setdefault(
(cls, args, tuple(kargs.items())),
cls(*args, **kargs))
class Spam(FlyweightMixin):
def __init__(self, a, b):
self.a = a
self.b = b
class Egg(FlyweightMixin):
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam.get_instance(1, 2) is Spam.get_instance(1, 2)
assert Egg.get_instance('a', 'b') is Egg.get_instance('a', 'b')
assert Spam.get_instance(1, 2) is not Egg.get_instance(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
唯一不爽的是调用方式:XX.get_instance(A, B),不够高端
class FlyweightMixin(object):
_instances = dict()
def __init__(self, *args, **kargs):
raise NotImplementedException
def __new__(cls, *args, **kargs):
return cls._instances.setdefault(
(cls, args, tuple(kargs.items())),
super(type(cls), cls).__new__(cls, *args, **kargs))
class Spam(FlyweightMixin):
def __init__(self, a, b):
self.a = a
self.b = b
class Egg(FlyweightMixin):
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
嗯, 这样就和以前一样好看了,可是 什么文艺青年? 差得很远, 一个想成为文艺青年的炫技版:
@classmethod
def _get_instance(cls, *args, **kargs):
return cls.__instances.setdefault(
(args, tuple(kargs.items())),
super(type(cls), cls).__new__(*args, **kargs))
def flyweight(decoree):
decoree.__instances = dict()
decoree.__new__ = _get_instance
return decoree
@flyweight
class Spam(object):
def __init__(self, a, b):
self.a = a
self.b = b
@flyweight
class Egg(object):
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
无语的文艺,好吧,现在就大众经常看见的文艺青年(穿着文艺,其实骨子里不文艺)版
class MetaFlyweight(type):
def __init__(cls, *args, **kargs):
type.__init__(cls, *args, **kargs)
cls.__instances = dict()
cls.__new__ = cls._get_instance
def _get_instance(cls, *args, **kargs):
return cls.__instances.setdefault(
(args, tuple(kargs.items())),
super(cls, cls).__new__(*args, **kargs))
class Spam(object):
__metaclass__ = MetaFlyweight
def __init__(self, a, b):
self.a = a
self.b = b
class Egg(object):
__metaclass__ = MetaFlyweight
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
这个当然也可以搞成类方法的风格,我只列出关键的代码
@classmethod
def _get_instance(cls, *args, **kargs):
return cls.__instances.setdefault(
(args, tuple(kargs.items())),
super(type(cls), cls).__new__(*args, **kargs))
def metaflyweight(name, parents, attrs):
cls = type(name, parents, attrs)
cls.__instances = dict()
cls.__new__ = _get_instance
return cls
好吧,终极的文艺青年版- 这是一个纯函数式使用元类的方法:
metaflyweight = lambda name, parents, attrs: type(
name,
parents,
dict(attrs.items() + [
('__instances', dict()),
('__new__', classmethod(
lambda cls, *args, **kargs: cls.__instances.setdefault(
tuple(args),
super(type(cls), cls).__new__(*args, **kargs))
)
)
])
)
class Spam(object):
__metaclass__ = metaflyweight
def __init__(self, a, b):
self.a = a
self.b = b
class Egg(object):
__metaclass__ = metaflyweight
def __init__(self, x, y):
self.x = x
self.y = y
assert Spam(1, 2) is Spam(1, 2)
assert Egg('a', 'b') is Egg('a', 'b')
assert Spam(1, 2) is not Egg(1, 2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
你到了那个境界呢?