【python 類】【部分轉發】設計模式 -- 享元模式

今天看https://www.cnblogs.com/alex3714/p/5760582.htmlhtml

 

看到享元模式時,真的感受長見識了~~~python

最好的例子就是:繪製有1W個星星,若是把從生成1W個實例,變成20個實例。 (此時享元模式就是最佳的解決方案)。ide

 

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 
 5 # Flyweight模式,顧名思義,就是共享元數據
 6 # 在咱們面向對象設計過程當中,咱們經常會面臨着對象實例過多的問題,若是對象實例過多這將是咱們系統性能提升的一個瓶頸。
 7 # 假設咱們要設計一個星空場景,如今咱們須要實例星星對象,咱們能夠實例每一顆星星,但隨着咱們實例星星對象增多整個場景就愈來愈慢了,
 8 # 若是你實例了1000+顆星星要你去維護,這但是一個吃力不討好的工做。咱們必須找到一個合適的方法解決以上問題,這就是今天要介紹的享元模式(Flyweight)。
 9 
10 # 享元模式(Flyweight):運用共享的技術有效地支持大量細粒度的對象。
11 #
12 # 抽象享元角色(Flyweight):此角色是全部的具體享元類的超類,爲這些類規定出須要實現的公共接口或抽象類。那些須要外部狀態(External State)的操做能夠經過方法的參數傳入。抽象享元的接口使得享元變得可能,可是並不強制子類實行共享,所以並不是全部的享元對象都是能夠共享的。
13 #
14 # 具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。若是有內部狀態的話,必須負責爲內部狀態提供存儲空間。享元對象的內部狀態必須與對象所處的周圍環境無關,從而使得享元對象能夠在系統內共享。有時候具體享元角色又叫作單純具體享元角色,由於複合享元角色是由單純具體享元角色經過複合而成的。
15 #
16 # 複合享元(UnsharableFlyweight)角色:複合享元角色所表明的對象是不能夠共享的,可是一個複合享元對象能夠分解成爲多個自己是單純享元對象的組合。複合享元角色又稱作不可共享的享元對象。這個角色通常不多使用。
17 #
18 # 享元工廠(FlyweightFactoiy)角色:本角色負責建立和管理享元角色。本角色必須保證享元對象能夠被系統適當地共享。當一個客戶端對象請求一個享元對象的時候,享元工廠角色須要檢查系統中是否已經有一個符合要求的享元對象,若是已經有了,享元工廠角色就應當提供這個已有的享元對象;若是系統中沒有一個適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。
19 #
20 # 客戶端(Client)角色:本角色還須要自行存儲全部享元對象的外部狀態。
21 #
22 # 內部狀態與外部狀態:在享元對象內部而且不會隨着環境改變而改變的共享部分,能夠稱之爲享元對象的內部狀態,反之隨着環境改變而改變的,不可共享的狀態稱之爲外部狀態。
23 
24 
25 class FlyweightBase(object):
26     _instances = dict()
27 
28     def __init__(self, *args, **kwargs):
29         # 繼承的子類必須初始化
30         raise NotImplementedError
31 
32     def __new__(cls, *args, **kwargs):
33         # print(cls._instances,type(cls))
34         return cls._instances.setdefault(
35             (cls, args, tuple(kwargs.items())),
36 
37             super(FlyweightBase, cls).__new__(cls)
38         )
39 
40     def test_data(self):
41         pass
42 
43 
44 class Spam(FlyweightBase):
45     '''精子類'''
46 
47     def __init__(self, a, b):
48         self.a = a
49         self.b = b
50 
51     def test_data(self):
52         print("精子準備好了", self.a, self.b)
53 
54 
55 class Egg(FlyweightBase):
56     '''卵類'''
57 
58     def __init__(self, x, y):
59         self.x = x
60         self.y = y
61 
62     def test_data(self):
63         print("卵子準備好了", self.x, self.y)
64 
65 
66 spam1 = Spam(1, 'abc')
67 spam2 = Spam(1, 'abc')
68 spam3 = Spam(3, 'DEF')
69 
70 print(id(spam1), id(spam2), id(spam3))
71 # 4417487928 4417487928 4417487984
72 
73 egg1 = Egg(1, 'abc')
74 egg2 = Egg(4,'abc')
75 print(id(egg1), id(egg2))
76 # 4417488096 4417488152
77 
78 assert spam1 is spam2
79 # 斷言正確
80 
81 assert egg1 is not spam1
82 # 斷言正確
83 
84 spam2.test_data()
85 egg1.test_data()
86 print(egg1._instances)
87 # {(<class '__main__.Spam'>, (1, 'abc'), ()): <__main__.Spam object at 0x1074d8438>, 
88 #  (<class '__main__.Spam'>, (3, 'DEF'), ()): <__main__.Spam object at 0x1074d8470>, 
89 #  (<class '__main__.Egg'>, (1, 'abc'), ()): <__main__.Egg object at 0x1074d84e0>, 
90 #  (<class '__main__.Egg'>, (4, 'abc'), ()): <__main__.Egg object at 0x1074d8518>}
91 
92 
93 print(egg1._instances.keys())
94 # [(<class '__main__.Spam'>, (1, 'abc'), ()), 
95 #  (<class '__main__.Spam'>, (3, 'DEF'), ()), 
96 #  (<class '__main__.Egg'>, (1, 'abc'), ()), 
97 #  (<class '__main__.Egg'>, (4, 'abc'), ())]
享元模式代碼

 

實現的關鍵是利用了字典的key能夠經過tuple 帶不少的信息~~~ 性能

 

收穫:平時使用時,也應該考慮使用tuple做爲key~~spa

相關文章
相關標籤/搜索