2020-12-15 《大話設(shè)計(jì)模式》之 設(shè)計(jì)原則 與 裝飾模式

幾個(gè)設(shè)計(jì)原則

1. 單一職責(zé)原則

2. 開(kāi)放-封閉原則

Open for extension, closed for modification.
對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉(接受現(xiàn)實(shí)质和,擁抱未來(lái));
面對(duì)需求臂港,對(duì)程序的改動(dòng)是通過(guò)增加新代碼進(jìn)行的诫给,而不是更改現(xiàn)有的代碼柠贤;
建立抽象进栽,分離克胳,令代碼可維護(hù)平绩、可擴(kuò)展、可復(fù)用漠另、靈活性好捏雌;
但是盡量在開(kāi)發(fā)初期就知道可能發(fā)生的變化,查明可能發(fā)生的變化等待的時(shí)間越長(zhǎng)笆搓,要?jiǎng)?chuàng)建正確的抽象就越困難性湿;
拒絕不成熟的抽象。

3. 依賴倒轉(zhuǎn)原則

強(qiáng)內(nèi)聚 松耦合

高層模塊不應(yīng)該依賴低層模塊满败,兩個(gè)都應(yīng)該依賴抽象
抽象不應(yīng)該依賴細(xì)節(jié)肤频,細(xì)節(jié)應(yīng)該依賴抽象

程序中的所有依賴關(guān)系都終止于抽象類(lèi)或者接口

里氏代換原則(LSP):子類(lèi)型必須能夠替換掉他們的父類(lèi)型


裝飾模式

1. 基礎(chǔ)類(lèi):

  • 基礎(chǔ)接口 定義一系列操作
  • 基礎(chǔ)裝飾類(lèi) 初始化時(shí)傳入基礎(chǔ)接口類(lèi)并儲(chǔ)存 操作時(shí)對(duì)儲(chǔ)存的基礎(chǔ)接口類(lèi)進(jìn)行操作達(dá)到串聯(lián)的效果(類(lèi)似 super().interface_method())

2. 實(shí)例化:

  • 自定義基礎(chǔ)接口的不同實(shí)現(xiàn)1
  • 自定義基礎(chǔ)接口的不同實(shí)現(xiàn)2
  • ...
  • 自定義裝飾類(lèi)1 對(duì)基礎(chǔ)接口的部分操作重寫(xiě) 重寫(xiě)時(shí)必須對(duì)基礎(chǔ)裝飾類(lèi)在初始化儲(chǔ)存的基礎(chǔ)接口類(lèi)的同名函數(shù)進(jìn)行調(diào)用以達(dá)到串聯(lián)的效果
    并且可以在調(diào)用前后執(zhí)行任意任務(wù)裝飾的關(guān)鍵步驟在這里
  • 自定義裝飾類(lèi)2 同上
  • ...

3. 使用:

未使用裝飾的基本用法:對(duì)基礎(chǔ)接口的實(shí)現(xiàn),實(shí)例化葫录,然后執(zhí)行一系列操作
使用裝時(shí)候:將實(shí)例連續(xù)包裹傳入自定義裝飾類(lèi)(注意裝飾的順序會(huì)影響執(zhí)行結(jié)果)着裹,再執(zhí)行一系列操作

4. 示例一(所有interface的methods均為需要被實(shí)現(xiàn)的實(shí)例方法):

# decorator_demo_for_instance_methods.py
from abc import ABC, abstractmethod


class Notice(ABC):
    """Base Component
    must implement get_content(extra info) and
    notify(routine method exposed to external)
    """
    @abstractmethod
    def get_content(self) -> str:
        pass
    @abstractmethod
    def notify(self):
        pass
class SimpleNotice(Notice):
    """Component Implementation"""
    def get_content(self) -> str:
        return "Notice Content"
    def notify(self):
        print(f"Console Notice: {self.get_content()}")


class Decorator(Notice):
    """Base Decorator
    1. Pass and save the base component while initializing
    2. Re-write method get_content(for extra info) 
    and most importantly, the routine method notify,
    by calling the original method

    Notice:
        The decorator was inherited from Notice, so every abstract
        method, including property method(if any) should be re-write
    """
    _notice: Notice = None
    def __init__(self, notice: Notice) -> None:
        self._notice = notice
    @property
    def notice(self) -> str:
        return self._notice
    def get_content(self) -> str:
        """Calling the original method"""
        return self.notice.get_content()
    def notify(self):
        """Calling the original method"""
        self.notice.notify()

class EmailDecorator(Decorator):
    """Decorator Variant 1
    re-write the routine method, which is the notify method
    do something before/after the routing method
    """
    def notify(self):
        print(f"Email Notified: {self.get_content()}")
        self.notice.notify()
        print(f"Email Decorator After")

class WeChatDecorator(Decorator):
    """Decorator Variant 2"""
    def notify(self):
        print(f"WeChat Notified: {self.get_content()}")
        self.notice.notify()
        print(f"WeChat Decorator After")

def client_code(notice: Notice) -> None:
    # Call the routine method, the notice variable passed
    # might be a subclass directly inherited from Notice
    # or the wrapper wrapped by the decorator
    notice.notify()


if __name__ == "__main__":
    # This way the client code can support both simple notices...
    simple = SimpleNotice()
    print("Client: Calling a routine for a simple notice:")
    client_code(simple)
    print("")

    # ...as well as decorated ones.
    #
    # Note how decorators can wrap not only simple notices but the other
    # decorators as well.
    # BTW, the order mattters
    decorator1 = EmailDecorator(simple)
    decorator2 = WeChatDecorator(decorator1)
    print("Client: Decorated notice:")
    client_code(decorator2)

Outputs:

$ python decorator_demo_for_instance_methods.py
Client: Calling a routine for a simple notice:
Console Notice: Notice Content

Client: Decorated notice:
WeChat Notified: Notice Content
Email Notified: Notice Content
Console Notice: Notice Content
Email Decorator After
WeChat Decorator After

5. 示例二:需要實(shí)現(xiàn)property abstractmethod(這里沒(méi)有寫(xiě)出完整的代碼领猾,僅點(diǎn)出要點(diǎn)米同,詳細(xì)的實(shí)現(xiàn)流程參照4)

class MyProperty:
    def __set_name__(self, owner, name):
        self.private_name = "_" + name
    def __get__(self, obj, objtype=None):
        return getattr(obj, self.private_name)
    def __set__(self, obj, value):
        setattr(obj, self.private_name, value)
class Component:
    @property
    @abstractmethod
    def p(self):
        pass
class ConcreteComponent(Component):
    p = MyProperty()
class Decorator(Component):
    p = MyProperty() # Decorator must rewrite the descriptor

Keywords

design principle, decorator, single responsibility principle

參考

  1. 《大話設(shè)計(jì)模式》, 2007年7月,作者程杰
  2. Design Pattern - Refactoring
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末摔竿,一起剝皮案震驚了整個(gè)濱河市面粮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌继低,老刑警劉巖熬苍,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異袁翁,居然都是意外死亡柴底,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)粱胜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)柄驻,“玉大人,你說(shuō)我怎么就攤上這事焙压『枧В” “怎么了抑钟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)野哭。 經(jīng)常有香客問(wèn)我在塔,道長(zhǎng),這世上最難降的妖魔是什么拨黔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任蛔溃,我火速辦了婚禮,結(jié)果婚禮上篱蝇,老公的妹妹穿的比我還像新娘城榛。我一直安慰自己,他們只是感情好态兴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布狠持。 她就那樣靜靜地躺著,像睡著了一般瞻润。 火紅的嫁衣襯著肌膚如雪喘垂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天绍撞,我揣著相機(jī)與錄音正勒,去河邊找鬼。 笑死傻铣,一個(gè)胖子當(dāng)著我的面吹牛章贞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播非洲,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸭限,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了两踏?” 一聲冷哼從身側(cè)響起败京,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梦染,沒(méi)想到半個(gè)月后赡麦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帕识,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年泛粹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肮疗。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晶姊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出族吻,到底是詐尸還是另有隱情帽借,我是刑警寧澤珠增,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站砍艾,受9級(jí)特大地震影響蒂教,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜脆荷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一凝垛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜓谋,春花似錦梦皮、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至观堂,卻和暖如春让网,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背师痕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工溃睹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胰坟。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓因篇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親笔横。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竞滓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容