在很多人的印象里,Python 作為一款動(dòng)態(tài)編程語(yǔ)言,在日常開(kāi)發(fā)中也很少涉及到設計模式
事實(shí)上,任何一個(gè)編程語(yǔ)言都可以使用設計模式,它可以保證代碼的規范性,只是每一種語(yǔ)言的實(shí)現方式略有不同而已
今天我們聊聊 Python 面試中,常被問(wèn)到的 5 種設計模式,它們是:單例模式、工廠(chǎng)模式、構建者模式、代理模式、觀(guān)察者模式
單例模式,是最簡(jiǎn)單常用的設計模式,主要目的是保證某一個(gè)實(shí)例對象只會(huì )存在一個(gè),減少資源的消耗
Python 單例模式有很多實(shí)現方式,這里推薦下面 2 種
第 1 種,重寫(xiě) __new__ 方法
定義一個(gè)實(shí)例變量,在 __new__ 方法中保證這個(gè)變量?jì)H僅初始化一次
# 單例模式
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance使用方式如下:
if __name__ == '__main__':
# 構建3個(gè)實(shí)例
instance1 = Singleton()
instance2 = Singleton()
instance3 = Singleton()
# 打印出實(shí)例的內存地址,判斷是否是同一個(gè)實(shí)例
print(id(instance1))
print(id(instance2))
print(id(instance3))第 2 種,閉包定義裝飾器
使用閉包的方式定義一個(gè)單例裝飾器,將類(lèi)的定義隱藏到閉包函數中
def singleton(cls):
"""
定義單例的裝飾器(閉包)
:param cls:
:return:
"""
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
使用上面裝飾器的類(lèi),構建的實(shí)例都能保證單例存在
@singleton
class Singleton(object):
"""單例實(shí)例"""
def __init__(self, arg1):
self.arg1 = arg1
使用方式如下:
if __name__ == '__main__':
instance1 = Singleton("xag")
instance2 = Singleton("xingag")
print(id(instance1))
print(id(instance2))需要注意的是,上面 2 種方式創(chuàng )建的單例并不適用于多線(xiàn)程
要保證多線(xiàn)程中構建的實(shí)例對象為單例,需要在 __new__ 函數中使用 threading.Lock() 加入同步鎖
class Singleton(object):
"""
實(shí)例化一個(gè)對象
"""
# 鎖
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance使用的時(shí)候,在線(xiàn)程任務(wù)中實(shí)例化對象,運行線(xiàn)程即可
def task(arg):
"""
任務(wù)
:param arg:
:return:
"""
instance = Singleton()
print(id(instance), '\n')
if __name__ == '__main__':
# 3個(gè)線(xiàn)程
for i in range(3):
t = threading.Thread(target=task, args=[i, ])
t.start()這樣,就保證了多線(xiàn)程創(chuàng )建的實(shí)例是單例存在的,不會(huì )導致臟數據!
# 定義一系列水果
class Apple(object):
"""蘋(píng)果"""
def __repr__(self):
return "蘋(píng)果"
class Banana(object):
"""香蕉"""
def __repr__(self):
return "香蕉"
class Orange(object):
"""橘子"""
def __repr__(self):
return "橘子"class FactorySimple(object):
"""簡(jiǎn)單工廠(chǎng)模式"""
@staticmethod
def get_fruit(fruit_name):
if 'a' == fruit_name:
return Apple()
elif 'b' == fruit_name:
return Banana()
elif 'o' == fruit_name:
return Orange()
else:
return '沒(méi)有這種水果'if __name__ == '__main__':
# 分別獲取3種水果
# 輸入參數,通過(guò)簡(jiǎn)單工廠(chǎng),返回對應的實(shí)例
instance_apple = FactorySimple.get_fruit('a')
instance_banana = FactorySimple.get_fruit('b')
instance_orange = FactorySimple.get_fruit('o')import abc
from factory.fruit import *
class AbstractFactory(object):
"""抽象工廠(chǎng)"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get_fruit(self):
passclass AppleFactory(AbstractFactory):
"""生產(chǎn)蘋(píng)果"""
def get_fruit(self):
return Apple()
class BananaFactory(AbstractFactory):
"""生產(chǎn)香蕉"""
def get_fruit(self):
return Banana()
class OrangeFactory(AbstractFactory):
"""生產(chǎn)橘子"""
def get_fruit(self):
return Orange()if __name__ == '__main__':
# 每個(gè)工廠(chǎng)負責生產(chǎn)自己的產(chǎn)品也避免了我們在新增產(chǎn)品時(shí)需要修改工廠(chǎng)的代碼,而只要增加相應的工廠(chǎng)即可
instance_apple = AppleFactory().get_fruit()
instance_banana = BananaFactory().get_fruit()
instance_orange = OrangeFactory().get_fruit()
print(instance_apple)
print(instance_banana)
print(instance_orange)
class MaoXW_CC(object):
"""川菜-毛血旺"""
def __str__(self):
return "川菜-毛血旺"
class XiaoCR_CC(object):
"""川菜-小炒肉"""
def __str__(self):
return "川菜-小炒肉"
class MaoXW_XC(object):
"""湘菜-毛血旺"""
def __str__(self):
return "湘菜-毛血旺"
class XiaoCR_XC(object):
"""湘菜-小炒肉"""
def __str__(self):
return "湘菜-小炒肉"class AbstractFactory(object):
"""
抽象工廠(chǎng)
既可以生產(chǎn)毛血旺,也可以生成小炒肉
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def product_maoxw(self):
pass
@abc.abstractmethod
def product_xiaocr(self):
pass
class CCFactory(AbstractFactory):
"""川菜館"""
def product_maoxw(self):
return MaoXW_CC()
def product_xiaocr(self):
return XiaoCR_CC()
class XCFactory(AbstractFactory):
"""湘菜館"""
def product_maoxw(self):
return MaoXW_XC()
def product_xiaocr(self):
return XiaoCR_XC()
if __name__ == '__main__':
# 川菜炒兩個(gè)菜,分別是:毛血旺和小炒肉
maoxw_cc = CCFactory().product_maoxw()
xiaocr_cc = CCFactory().product_xiaocr()
print(maoxw_cc, xiaocr_cc)
maoxw_xc = XCFactory().product_maoxw()
xiaocr_xc = XCFactory().product_xiaocr()
print(maoxw_xc, xiaocr_xc)單例模式和工廠(chǎng)模式是日常使用最為頻繁的兩種設計模式,下篇文章將聊聊后面 3 種設計模式
聯(lián)系客服