Python 的物件導向特性讓設計模式的實踐更為靈活。代理模式提供對物件的控制存取,適合實作懶載入,減少不必要的計算與資源消耗。透過 __get__ 描述器方法,我們可以控制屬性存取行為,實作延遲初始化。同時,MVC 架構的應用在終端機程式設計中,能有效分離關注點,提高程式碼的可維護性和擴充性。模型負責資料和邏輯,檢視負責呈現,控制器協調兩者互動,使程式結構更清晰。

車輛類別定義

首先,我們定義一個 Car 類別,包含車輛的基本屬性和方法。這個類別將包含車輛的型別、顏色和位置等屬性。

import random

class CarType:
    subcompact = "subcompact"
    compact = "compact"
    suv = "suv"

class Car:
    def __init__(self, car_type):
        self.car_type = car_type

    def render(self, color, x, y):
        print(f"渲染 {self.car_type} 車輛,顏色:{color}, 位置:({x}, {y})")

車輛渲染與統計

接下來,我們將建立一個主函式,負責渲染不同的車輛型別和統計渲染的車輛數量。

def main():
    min_point, max_point = 0, 100
    colors = ["紅色", "藍色", "綠色", "黃色", "黑色", "白色"]
    car_counter = 0

    # 渲染 subcompact 車輛
    for _ in range(10):
        c1 = Car(CarType.subcompact)
        c1.render(random.choice(colors), random.randint(min_point, max_point), random.randint(min_point, max_point))
        car_counter += 1

    # 渲染 compact 車輛
    for _ in range(3):
        c2 = Car(CarType.compact)
        c2.render(random.choice(colors), random.randint(min_point, max_point), random.randint(min_point, max_point))
        car_counter += 1

    # 渲染 suv 車輛
    for _ in range(5):
        c3 = Car(CarType.suv)
        c3.render(random.choice(colors), random.randint(min_point, max_point), random.randint(min_point, max_point))
        car_counter += 1

    print(f"渲染的車輛數量:{car_counter}")

if __name__ == "__main__":
    main()

執行結果

執行這個程式將會渲染不同型別的車輛,並統計渲染的車輛數量。每次執行都會因為隨機的位置和顏色而產生不同的結果。

圖表翻譯:

  flowchart TD
    A[開始] --> B[定義車輛類別]
    B --> C[渲染車輛]
    C --> D[統計渲染車輛數量]
    D --> E[輸出結果]

這個流程圖描述了程式的執行流程,從定義車輛類別開始,到渲染車輛,然後統計渲染的車輛數量,最後輸出結果。

實作 Flyweight 模式

在這個例子中,我們將實作 Flyweight 模式來最佳化車輛物件的建立。Flyweight 模式是一種結構模式,用於減少物件的數量,從而節省記憶體空間。

車輛類別

首先,我們定義一個 Car 類別,代表一輛車。這個類別有兩個屬性:car_typecolor

from enum import Enum
import random

class CarType(Enum):
    SUBCOMPACT = 1
    COMPACT = 2
    SUV = 3

class Car:
    pool = {}

    def __new__(cls, car_type):
        if car_type not in cls.pool:
            cls.pool[car_type] = super().__new__(cls)
            cls.pool[car_type].car_type = car_type
        return cls.pool[car_type]

    def render(self, color, x, y):
        print(f'render a car of type {self.car_type} and color {color} at ({x}, {y})')

主函式

在主函式中,我們建立了多輛車,並使用 Flyweight 模式來最佳化車輛物件的建立。

def main():
    c1 = Car(CarType.SUBCOMPACT)
    c2 = Car(CarType.COMPACT)
    c3 = Car(CarType.SUV)

    c1.render('yellow', 57, 51)
    c2.render('blue', 10, 61)
    c3.render('gray', 65, 74)

    c4 = Car(CarType.SUBCOMPACT)
    c5 = Car(CarType.SUBCOMPACT)
    c6 = Car(CarType.SUV)

    print(f'{id(c4)} == {id(c5)}? {id(c4) == id(c5)}')
    print(f'{id(c5)} == {id(c6)}? {id(c5) == id(c6)}')

    print(f'cars actually created: {len(Car.pool)}')

if __name__ == '__main__':
    main()

執行結果

執行這個程式會輸出以下結果:

render a car of type CarType.SUBCOMPACT and color yellow at (57, 51)
render a car of type CarType.COMPACT and color blue at (10, 61)
render a car of type CarType.SUV and color gray at (65, 74)
render a car of type CarType.SUBCOMPACT and color red at (10, 19)
render a car of type CarType.SUBCOMPACT and color green at (89, 5)
render a car of type CarType.SUBCOMPACT and color green at (88, 76)
render a car of type CarType.SUBCOMPACT and color black at (0, 18)
render a car of type CarType.SUBCOMPACT and color silver at (10, 19)
1396248720328 == 1396248720328? True
1396248720328 == 1396248720640? False
cars actually created: 3

這個結果表明,相同型別的車輛物件被重複使用,從而節省了記憶體空間。

MVC 模式:軟體開發中的分離關注點

MVC(Model-View-Controller)模式是一種軟體設計模式,主要用於應用程式開發,旨在提高軟體的維護性和可擴充套件性。這種模式是根據分離關注點(Separation of Concerns,SoC)原則,將應用程式分成三個主要部分:模型(Model)、檢視(View)和控制器(Controller)。

模型(Model)

模型是MVC模式的核心部分,代表著知識和商業邏輯。它包含和管理著應用程式的資料、狀態和規則。模型是應用程式的核心,負責處理資料的儲存、查詢和更新。

檢視(View)

檢視是模型的視覺化呈現,負責顯示資料給使用者。檢視可以是圖形使用者介面(GUI)、文字輸出、手機應用程式的GUI、PDF檔案、圖表等。檢視只負責顯示資料,不處理資料。

控制器(Controller)

控制器是模型和檢視之間的連結,負責處理使用者的輸入和互動。控制器接收使用者的請求,處理請求,然後更新模型和檢視。

MVC模式的工作流程

  1. 使用者觸發檢視的事件(例如點選按鈕)。
  2. 檢視通知控制器使用者的動作。
  3. 控制器處理使用者的輸入,與模型互動。
  4. 模型進行必要的驗證和狀態變化,通知控制器。
  5. 控制器指示檢視更新和顯示輸出。

MVC模式的優點

MVC模式提供了多個優點,包括:

  • 分離關注點:MVC模式將應用程式分成三個部分,各部分負責不同的功能,提高了維護性和可擴充套件性。
  • 多檢視支援:MVC模式允許使用多個檢視,甚至可以在同一時間使用多個檢視。
  • 減少耦合:MVC模式減少了模型和檢視之間的耦合,提高了應用程式的靈活性。

實際應用

MVC模式在許多領域中被廣泛使用,包括:

  • Web開發:Web2py、Django等框架都使用MVC模式。
  • 手機應用程式開發:MVC模式被用於手機應用程式開發中,例如iOS和Android。
  • 桌面應用程式開發:MVC模式也被用於桌面應用程式開發中,例如Windows和macOS。

MVC 模式的優點和實作

MVC(Model-View-Controller)是一種非常通用且有用的設計模式。所有流行的網頁框架(Django、Rails、Symfony 或 Yii)和應用框架(iPhone SDK、Android 和 QT)都使用了 MVC 或其變體(MVA、MVP 等)。即使不使用這些框架,實作 MVC 也很有意義,因為它提供了以下優點:

  • 分離檢視和模型:允許圖形設計師專注於 UI 部分,程式設計師專注於開發,無需彼此幹擾。
  • 鬆散耦合:檢視和模型之間的鬆散耦合使得每個部分可以被修改或擴充套件,而不會影響到其他部分。例如,新增一個新的檢視非常簡單,只需要實作一個新的控制器。
  • 維護:每個部分的責任都很明確,因此維護更容易。

實作 MVC 時,需要確保建立智慧模型、薄控制器和愚笨檢視。

  • 智慧模型
    • 包含所有驗證、業務規則和邏輯。
    • 處理應用程式的狀態。
    • 可以存取應用程式資料(資料函式庫、雲端儲存等)。
    • 不依賴於 UI。
  • 薄控制器
    • 更新模型當使用者與檢視互動時。
    • 更新檢視當模型發生變化時。
    • 處理資料在傳遞給模型或檢視之前(如果需要)。
    • 不顯示資料。
    • 不直接存取應用程式資料。
    • 不包含驗證、業務規則或邏輯。
  • 愚笨檢視
    • 顯示資料。
    • 允許使用者與之互動。
    • 僅進行最基本的處理(通常由框架提供,如使用簡單變數和迴圈控制)。
    • 不儲存任何資料。
    • 不直接存取應用程式資料。
    • 不包含驗證、業務規則或邏輯。

如果您正在從頭實作 MVC,並想知道是否做對了,可以嘗試回答一些關鍵問題:

  • 如果您的應用程式有 GUI,是否可以更改其外觀和風格?是否可以輕易地在執行時更改應用程式的皮膚?
  • 如果您的應用程式沒有 GUI(例如,終端應用程式),新增 GUI 支援是否容易?或者,新增檢視以顯示結果在圖表(餅圖、柱狀圖等)或檔案(PDF、電子試算表等)中是否容易?如果這些更改不是微不足道的(建立一個新的控制器,附加一個檢視,不修改模型),則意味著 MVC 沒有被正確實作。

實作 MVC

以下是一個簡單的實作 MVC 的例子:一個報價印表機。使用者輸入一個數字,然後看到與該數字相關的報價。報價儲存在一個元組中,這通常是儲存在資料函式庫、檔案等中的資料,只有模型可以直接存取它。

# 報價模型
class QuoteModel:
    def get_quote(self, n):
        try:
            value = quotes[n]
        except IndexError as err:
            value = 'Not found!'
        return value

# 報價檢視(終端)
class QuoteTerminalView:
    def show(self, quote):
        print(f'And the quote is: "{quote}"')

    def error(self, msg):
        print(f'Error: {msg}')

# 報價控制器
class QuoteController:
    def __init__(self):
        self.model = QuoteModel()
        self.view = QuoteTerminalView()

    def run(self):
        self.view.show(self.model.get_quote(1))

# 報價資料
quotes = (
    'A man is not complete until he is married. Then he is finished.',
    'As I said before, I never repeat myself.',
    'Behind a successful man is an exhausted woman.',
    'Black holes really suck...',
    'Facts are stubborn things.'
)

# 執行報價控制器
if __name__ == '__main__':
    controller = QuoteController()
    controller.run()

這個例子展示瞭如何使用 MVC 模式建立一個簡單的報價印表機。模型負責儲存和管理報價資料,檢視負責顯示報價,控制器負責更新模型和檢視。這種設計使得應用程式更易於維護和擴充套件。

MVC 架構在終端機應用中的實作

在設計終端機應用時,MVC(Model-View-Controller)架構是一種常見的設計模式。它將應用程式分為三個主要部分:模型(Model)、檢視(View)和控制器(Controller)。這種分離使得程式碼更容易維護和擴充套件。

模型(Model)

模型代表了應用程式的資料和商業邏輯。它負責儲存和管理資料,在這個例子中,是一系列的名言。模型不需要知道如何顯示資料或如何與使用者互動。

class QuoteModel:
    def __init__(self):
        self.quotes = [
            "Believe you can and you're halfway there. - Theodore Roosevelt",
            "The only way to do great work is to love what you do. - Steve Jobs",
            # ...
        ]

    def get_quote(self, n):
        try:
            return self.quotes[n]
        except IndexError:
            return None

檢視(View)

檢視負責顯示資料給使用者。它定義了使用者介面的外觀和感覺。在這個例子中,檢視是一個簡單的終端機介面,使用者可以在其中選擇要檢視的名言。

class QuoteTerminalView:
    def select_quote(self):
        return input('Which quote number would you like to see? ')

    def show(self, quote):
        if quote is not None:
            print(quote)
        else:
            print("Invalid quote number.")

    def error(self, message):
        print(message)

控制器(Controller)

控制器是MVC架構的核心。它負責管理模型和檢視之間的互動。控制器接收使用者的輸入,更新模型,並告訴檢視如何顯示資料。

class QuoteTerminalController:
    def __init__(self):
        self.model = QuoteModel()
        self.view = QuoteTerminalView()

    def run(self):
        valid_input = False
        while not valid_input:
            try:
                n = self.view.select_quote()
                n = int(n)
                valid_input = True
            except ValueError as err:
                self.view.error(f"Incorrect index '{n}'")
        quote = self.model.get_quote(n)
        self.view.show(quote)

主函式(Main Function)

最後,主函式初始化和啟動控制器。

def main():
    controller = QuoteTerminalController()
    controller.run()

if __name__ == "__main__":
    main()

這個例子展示瞭如何使用MVC架構設計一個簡單的終端機應用。控制器負責管理模型和檢視之間的互動,模型儲存和管理資料,檢視顯示資料給使用者。這種分離使得程式碼更容易維護和擴充套件。

虛擬代理模式的應用

虛擬代理模式是一種結構性設計模式,主要用於延遲初始化,直到第一次需要使用物件時才建立。這種模式可以用於減少計算成本和記憶體使用。

虛擬代理模式的實作

以下是虛擬代理模式的實作示例:

class LazyProperty:
    def __init__(self, method):
        self.method = method
        self.method_name = method.__name__

    def __get__(self, instance, owner):
        if instance is None:
            return self
        value = self.method(instance)
        setattr(instance, self.method_name, value)
        return value

class MyClass:
    def __init__(self):
        pass

    @LazyProperty
    def expensive_property(self):
        # 模擬計算成本高的操作
        print("計算中...")
        return "結果"

obj = MyClass()
print(obj.expensive_property)  # 計算中... 結果
print(obj.expensive_property)  # 結果

在這個示例中,LazyProperty 類別用作裝飾器,延遲初始化 expensive_property 屬性,直到第一次需要使用時才計算。

保護代理模式的實作

保護代理模式用於控制對敏感物件的存取。以下是保護代理模式的實作示例:

class ProtectedProxy:
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, name):
        if name in ["敏感屬性1", "敏感屬性2"]:
            raise PermissionError("無權存取")
        return getattr(self.obj, name)

class MyClass:
    def __init__(self):
        self.敏感屬性1 = "敏感資料1"
        self.敏感屬性2 = "敏感資料2"
        self.公共屬性 = "公共資料"

obj = MyClass()
proxy = ProtectedProxy(obj)

print(proxy.公共屬性)  # 公共資料
try:
    print(proxy.敏感屬性1)
except PermissionError as e:
    print(e)  # 無權存取

在這個示例中,ProtectedProxy 類別用於控制對 MyClass 物件的存取,限制存取敏感屬性。

代理模式的應用:懶載入屬性

在 Python 中,代理模式(Proxy Pattern)是一種結構型設計模式,允許您提供對某個物件的控制存取。這個模式可以用於實作懶載入(Lazy Loading)機制,減少不必要的計算和記憶體使用。

代理模式的工作原理

代理模式的基本思想是建立一個代理物件,該物件代表著真正的物件,並控制對其的存取。代理物件可以延遲載入真正的物件,直到需要時才進行初始化。

實作懶載入屬性

要實作懶載入屬性,我們可以使用 Python 的 __get__()__set__()__delete__() 特殊方法。這些方法允許我們自訂屬性的存取行為。

以下是 LazyProperty 類別的實作:

class LazyProperty:
    def __init__(self, method):
        self.method = method
        self.method_name = method.__name__

    def __get__(self, obj, cls):
        if not obj:
            return None
        value = self.method(obj)
        setattr(obj, self.method_name, value)
        return value

在這個實作中,LazyProperty 類別接受一個方法作為引數,並將其儲存為 method 屬性。__get__() 方法負責存取屬性的值。如果屬性尚未初始化,則呼叫 method() 來計算其值,並使用 setattr() 將其儲存為物件的屬性。

使用 LazyProperty 類別

要使用 LazyProperty 類別,我們可以將其作為裝飾器,將其應用於需要懶載入的屬性。以下是 Test 類別的例子:

class Test:
    def __init__(self):
        self.x = 'foo'
        self.y = 'bar'
        self._resource = None

    @LazyProperty
    def resource(self):
        print(f'initializing self._resource which is: {self._resource}')
        # 初始化 _resource 屬性
        self._resource = ('resource', 'initialized')
        return self._resource

在這個例子中,resource 屬性被 LazyProperty 類別裝飾。當我們存取 resource 屬性時,__get__() 方法會被呼叫,計算其值並儲存為物件的屬性。

結果

使用 LazyProperty 類別,我們可以實作懶載入屬性,減少不必要的計算和記憶體使用。當我們存取 resource 屬性時,會列印初始化訊息,表明屬性已經被初始化。

test = Test()
print(test.resource)  # initializing self._resource which is: None
print(test.resource)  # ('resource', 'initialized')

在這個例子中,resource 屬性只會被初始化一次,之後的存取會直接傳回已經初始化的值。

懶初始化(Lazy Initialization)模式

在軟體開發中,懶初始化是一種常見的設計模式,用於延遲物件或資源的初始化,直到它們真正被需要。這種方法可以提高程式的效率,尤其是在初始化過程複雜或耗費資源的情況下。

從效能最佳化視角來看,本文探討了多種程式設計技巧,涵蓋物件建立、程式架構設計以及資源載入策略。透過Python程式碼範例,我們深入分析了Flyweight模式如何透過共用物件來減少記憶體消耗,以及MVC模式如何透過關注點分離提升程式碼維護性和可擴充套件性。此外,本文也闡述了代理模式,特別是虛擬代理和保護代理的應用,展示瞭如何延遲物件初始化以及控制物件存取,進一步最佳化效能和安全性。然而,這些模式並非銀彈,需根據實際場景選擇應用。例如,Flyweight模式適用於大量相似物件的建立,而代理模式則更適用於資源密集型或需要控制存取的物件。對於重視程式碼效能的開發者,建議深入理解這些模式的原理和應用場景,並結合專案需求進行技術選型。未來,隨著程式設計正規化的不斷演進,預計會有更多精細化的效能最佳化技術出現,例如更智慧的編譯器最佳化和更底層的硬體加速技術。持續關注這些新興技術,將有助於開發者構建更高效、更穩定的應用程式。