# SOLID SOLID pinciples S = Single Responsibility Princliples (SRP) O = Open Closed Princliples (OCP) L = Liskov Substitution Princliples (LSP) I = Interface Segregation Princliples (ISP) D = Dependency Inversion Princliples (DIP) ### Single Responsibility Princliples (SRP) 一個模組應該只對應一個腳色,如果一個模組需對應不同腳色,應該將模組切開,以方便程式設計、更動、測試。 假設今天一個店商平台後台有 Customer 的模組去計算 customer 消費金額並儲存到 Database,初次設計架構如下,但模組有些問題。 ``` class Customer: def __init__(self): pass def cal(self): return total def save_db(self): pass ``` 如果電商周年慶品項8折以及臨時需要更換 database,會導致一個 class 裡有兩個 function 需要更動,但根據 SCP 原則,一個模組應該只對應一個腳色,Customer 理應專注於消費金額,因此需要將 save_db 獨立出來,如使用不同的 db 則實例化不同的 class 。 ``` class Customer: def __init__(self): self.db = MysqldbCrud() def cal(self): return total def save_db(self): self.db.save_db() class MysqldbCrud: def __init__(self): pass def save_db(self): pass ``` ### Open Close Principle (OCP) 在原有系統新增功能時,應該在不修改既有程式的原則下去擴充新功能,例如當 chrome 或是 vscode extension,當他們下載新套件時不會影響到既有的套件。 ``` class chorme: _theme = "default" def set_theme(self, theme: str): self._theme = theme def apply_theme(self): activate() ``` ### Liskov Substitution Principle (LSP) 子類別必須要可以替換父類別的行為 例如: 當設計一個父類 class bird,裡面有 fly 和 eat 功能,有許多鳥類生物可以繼承class bird,但是雞和企鵝並不會飛,因此class bird 違反 LSP 原則。 違反 LSP ``` class bird: def fly(): ... def eat(): ... class penguin(bird): # penguin can not fly def fly(): ... def eat(): ... ``` 修改成以下 ``` class bird: def eat(): ... class flybird(bird): def fly(): ... def eat(): ... class flightlessbird(bird): def flightless(): ... def eat(): ... ``` ### Interface Segregation Principle (ISP) 模組之間的依賴不應該有用不到的功能能夠被呼叫。 例如: 違反ISP ``` class car: def start_engine(): ... def repair_wheel(): ... class driver: mycar = car() mycar.start_engine() # 一般使用者不應該可以呼叫 repair_wheel 功能 mycar.repair_wheel() ``` 修改後 ``` class user: def start_engine(): ... class engineer: def repair_wheel(): ... class UserCar(User): def __init__(self): super().__init__() class EngineerCar(Engineer): def __init__(self): super().__init__() ``` ### Dependency Inversion Principle (DIP) 將低層模組的控制權從原來的高層模組中抽離,將兩者的耦合只放在抽象層上。 例如: 當今天有多個 programmer 時,每次都需要重寫一次 class ,違反 DIP 原則 ``` class Product: def produce(): programmer = Meng() product = programmer.programming() return product ``` 修改後 ``` class Programmer: def programming(): ... class Meng(Programmer): def programmimg(): ... class Product: def produce(programmer: Programmer=Meng()): product = programmer.programming() return product ``` ## 參考 * https://medium.com/%E7%A8%8B%E5%BC%8F%E6%84%9B%E5%A5%BD%E8%80%85/%E4%BD%BF%E4%BA%BA%E7%98%8B%E7%8B%82%E7%9A%84-solid-%E5%8E%9F%E5%89%87-%E5%96%AE%E4%B8%80%E8%81%B7%E8%B2%AC%E5%8E%9F%E5%89%87-single-responsibility-principle-c2c4bd9b4e79 * https://ithelp.ithome.com.tw/articles/10230018 * https://medium.com/%E7%A8%8B%E5%BC%8F%E6%84%9B%E5%A5%BD%E8%80%85/%E4%BD%BF%E4%BA%BA%E7%98%8B%E7%8B%82%E7%9A%84-solid-%E5%8E%9F%E5%89%87-%E4%BB%8B%E9%9D%A2%E9%9A%94%E9%9B%A2%E5%8E%9F%E5%89%87-interface-segregation-principle-50f54473c79e * https://igouist.github.io/post/2020/12/oo-14-dependency-inversion-principle/ ## Thank you! :dash: You can find me on - GitHub: https://github.com/shaung08 - Email: a2369875@gmail.com