物件導向設計原則和模式

2022-07-09 15:01:06

物件導向設計原則

開放封閉原則:

  一個軟體實體如類、模組和函數應該對拓展開放,對修改關閉。即軟體實體應儘量在不修改原有程式碼的情況下進行擴充套件。

里氏替換原則:

  所有參照的父類別的地方必須能透明的使用其子類的物件

依賴倒置原則:

  高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象;即針對介面程式設計,而不是針對實現程式設計

工廠方法模式

定義:建立物件的介面(工廠介面),讓子類決定範例化哪一個產品類

角色:

  抽象工廠角色(creator)

  具體工廠角色(concrete creator)

  抽象產品角色(product)

  具體產品角色(concrete product)

例子:比如我們有一個染色的機器,我們要給指定的機器生產對應的工藝程式設計

from abc import ABCMeta, abstractmethod
#抽象產品
class CraftProgramming(metaclass=ABCMeta):
    #abstract class
    @abstractmethod
    def setStep(self,step: list):
        pass
#具體產品
class ModelTypeACraft(CraftProgramming):
    def __init__(self,childModelType=False):
        self.childModelType =childModelType
    def setStep(self,step: list):
        if self.childModelType:
            print(f"A機型-{self.childModelType}工藝工步為{step}")
        else:
            print(f"A機型工藝工步為{step}")

class ModelTypeBCraft(CraftProgramming):
    def setStep(self,step: list):
            print(f"B機型工藝工步為{step}")
#抽象工廠
class CraftProgrammingFactory(metaclass=ABCMeta):
    @abstractmethod
    def creatCraft(self):
        pass
#具體工廠
class ModelTypeACraftFactory(CraftProgrammingFactory):
    def creatCraft(self):
        return ModelTypeACraft()

class ModelTypeBCraftFactory(CraftProgrammingFactory):
    def creatCraft(self):
        return ModelTypeBCraft()

class ModelTypeAChildCraftFactory(CraftProgrammingFactory):
    def creatCraft(self):
        return ModelTypeACraft(childModelType=True)

cf = ModelTypeACraftFactory()
c = cf.creatCraft()
c.setStep([])

 優點:

  每一個具體產品對應一個具體工廠類,不需要修改工廠類的程式碼

  隱藏了物件建立的實現細節

缺點:

  每增加一個具體的產品,就必須增加一個對應的具體工廠類

抽象工廠模式

定義:一個工廠類介面,讓工廠子類建立一系列相關或互相依賴的物件

相比於工廠模式方法,抽象工廠模式中的每一個具體工廠都生產了一套產品

例子:我們延續上面的染色機工藝程式設計的例子,一個工藝我們分為工步、引數、工步型別

from abc import ABCMeta, abstractmethod
#抽象產品
class CraftParameter(metaclass=ABCMeta):
    #abstract class
    @abstractmethod
    def setParameter(self):
        pass

class CraftStep(metaclass=ABCMeta):
    #abstract class
    @abstractmethod
    def setStep(self,step: list):
        pass

class CraftFuntionType(metaclass=ABCMeta):
    #abstract class
    @abstractmethod
    def setFuntionType(self,funcType: int):
        pass

#抽象工廠
class CreatCraftFactory(metaclass=ABCMeta):
    @abstractmethod
    def creatParameter(self):
        pass

    @abstractmethod
    def creatStep(self):
        pass

    @abstractmethod
    def creatFuntionType(self):
        pass

#具體產品
class ModelTypeACraftParameter(CraftParameter):
    def setParameter(self):
        print("A機型工藝的引數")

class ModelTypeACraftStep(CraftStep):
    def setStep(self,step: list):
        print(f"A機型工藝的工步{step}")

class ModelTypeACraftFuntionType(CraftFuntionType):
    def setFuntionType(self,funcType: int):
        print(f"A機型工藝的工步型別{funcType}")

#具體工廠
class ModelTypeACreatCraftFactory(CreatCraftFactory):
    def creatParameter(self):
        return ModelTypeACraftParameter()

    def creatStep(self):
        return ModelTypeACraftStep()

    def creatFuntionType(self):
        return ModelTypeACraftFuntionType()

#使用者端
class Craft:
    def __init__(self,parameter,step,funtionType):
        self.parameter = parameter
        self.step = step
        self.funtionType = funtionType

    def craft_info(self):
        self.parameter.setParameter()
        self.step.setStep([])
        self.funtionType.setFuntionType(1)

def creatCraft(factory):
    parameter = factory.creatParameter()
    step = factory.creatStep()
    funtionType = factory.creatFuntionType()
    return Craft(parameter,step,funtionType)

c1 = creatCraft(ModelTypeACreatCraftFactory())
c1.craft_info()

優點:

  使用者端與類具體實現分離

  每個工廠都有一個完成的產品系列,易於交換產品系列和產品一致性

缺點:

  難以支援新的抽象產品

單例模式

定義:保證一個類只有一個範例,並提供一個存取他的全域性存取點

角色:singleton

優點:

  對唯一範例受控存取

  單例相當於全域性變數,防止名稱空間被汙染

  常用於紀錄檔、資料庫等

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"):
            cls._instance = super().__new__(cls)
        return cls._instance

class MyClass(Singleton):
    def __init__(self,a):
        self.a = a

a=MyClass(10)

b=MyClass(20)

print(a.a) #20
print(b.a) #20
print(id(a) , id(b)) #id相同

 介面卡模式

定義:將一個類介面轉換成客戶希望的另一個介面。介面卡使得原來介面不相容的現在可以一起工作

類介面卡:使用類的繼承

物件介面卡:使用組合

from abc import ABCMeta, abstractmethod

class CraftParameter(metaclass=ABCMeta):
    #abstract class
    @abstractmethod
    def setParameter(self):
        pass

class ModelACraftParameter(CraftParameter):
    def setParameter(self):
        print("A機型的工藝引數")

class ModelBCraftParameter(CraftParameter):
    def setParameter(self):
        print("B機型的工藝引數")

class ModelCCraftParameter:
    def insertParameter(self):
        print("C機型的工藝引數")

#這個時候我們發現C機型方法和A、B機型的方法不一致,我們需要去適配C機型
#第一種方法:類介面卡
class NewModelCraftParameter(CraftParameter,ModelCCraftParameter):
    def setParameter(self):
        self.insertParameter()

#第二種辦法:物件介面卡
class CraftParameterAdapter:
    def __init__(self,craftParameter):
        self.craftParameter = craftParameter

    def setParameter(self):
        self.craftParameter().insertParameter()

# c=NewModelCraftParameter()
# c.setParameter()
c=CraftParameterAdapter(ModelCCraftParameter)
c.setParameter()

 橋模式

角色:

  抽象

  細化抽象

  實現者

  具體實現者

場景:當事務有兩個以上維度,兩個維度都可以拓展

優點:

  抽象和實現分離

  具有優秀的拓展能力

from abc import ABCMeta, abstractmethod
#抽象
class Shape(metaclass=ABCMeta):
    def __init__(self,color):
        self.color = color
    @abstractmethod
    def draw(self):
        pass
#實現者
class Color(metaclass=ABCMeta):
    @abstractmethod
    def paint(self,shape):
        pass
#細化抽象
class Triangle(Shape):
    name = "三角形"
    def draw(self):
        self.color.paint(self)

class Circle(Shape):
    name = "三角形"
    def draw(self):
        self.color.paint(self)
#具體實現者
class Red(Color):
    def paint(self,shape):
        print(f"紅色的{shape.name}")

shape = Triangle(Red())
shape.draw()

 組合模式

適用於:部分--整體結構

優點:

  包含了基本物件和組合物件的類層次結構

  簡化使用者端程式碼,可以一致的使用組合物件和單個物件

  更容易增加新型別元件

from abc import ABCMeta, abstractmethod

#抽象元件
class ModelType(metaclass=ABCMeta):
    @abstractmethod
    def printModelType(self):
        pass

#葉子元件最小的節點
class SonModel(ModelType):
    def __init__(self, modelName):
        self.modelName = modelName

    def __str__(self):
        return f"機型{self.modelName}"

    def printModelType(self):
        print(self)

class ParentModelType(ModelType):
    def __init__(self,parentModelType,model):
        self.parentModelType = parentModelType
        self.model = model

    def __str__(self):
        return f"{self.parentModelType}旗下的[{self.model}]"

    def printModelType(self):
        print(self)
#複合元件
class Brand(ModelType):
    def __init__(self, iterable):
        self.sonModel = [m for m in iterable]

    def printModelType(self):
        for i in self.sonModel:
            i.printModelType()

# p = ParentModelType("setex757",SonModel("水流-02"))
# p.printModelType()
s1 = SonModel("水流-02")
p1 =ParentModelType("setex757",s1)
b = Brand([s1,p1])
b.printModelType()

 外觀模式

比較簡單:高層程式碼不需要知道低層程式碼,只需要用封裝好的就行

定義:為子系統的介面提空一個一致的介面,定義一個高層介面,這介面使得系統更容易使用

角色:

  外觀

  子系統類

優點:

  減少系統依賴

  提高靈活性

  提高安全性

class LendingSinger:
    def start(self):
        print("主唱開始唱")

    def stop(self):
        print("主唱閉嘴")

class Bass:
    def start(self):
        print("貝斯開始演奏")

    def stop(self):
        print("貝斯停止演奏")

class Keyboard:
    def start(self):
        print("鍵盤手開始演奏")

    def stop(self):
        print("鍵盤手停止演奏")

#更高階級別的類:樂隊
#通過高系統呼叫來封裝子系統
class Band:
    def __init__(self):
        self.lengdingSinger = LendingSinger()
        self.bass = Bass()
        self.keyboard = Keyboard()

    def start(self):
        self.bass.start()
        self.lengdingSinger.start()
        self.keyboard.start()

    def stop(self):
        self.keyboard.stop()
        self.bass.stop()
        self.lengdingSinger.stop()

b=Band()
b.start()
b.stop()

 模板方法模式

定義:先寫一個骨架,其中的一些細節可以延遲實現,模板方法可以使得子類不改變骨架就可以重新定義某些改變

角色:

  抽象類:定義原子操作(或者叫勾點操作),實現一個模板方法骨架

  具體類:實現原子操作

依舊拿上面的樂隊作為例子

from abc import ABCMeta , abstractmethod
from time import sleep


class Band:
    @abstractmethod
    def lengdingSinger(self):
        pass

    @abstractmethod
    def bass(self):
        pass

    @abstractmethod
    def keyboard(self):#原子操作
        pass

    def run(self): #模板方法
        self.bass()
        while True:
            try:
                self.lengdingSinger()
                sleep(1)
            except KeyboardInterrupt:
                break
        self.keyboard()
#原子操作定義好,等後面在子類裡面實現
class NewBand(Band):
    def lengdingSinger(self):
        print("主唱無伴奏solo")

    def bass(self):
        print("貝斯進")

    def keyboard(self):
        print("鍵盤手進")

b = NewBand().run()