幾個(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
參考
- 《大話設(shè)計(jì)模式》, 2007年7月,作者程杰
- Design Pattern - Refactoring