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_type
和 color
。
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模式的工作流程
- 使用者觸發檢視的事件(例如點選按鈕)。
- 檢視通知控制器使用者的動作。
- 控制器處理使用者的輸入,與模型互動。
- 模型進行必要的驗證和狀態變化,通知控制器。
- 控制器指示檢視更新和顯示輸出。
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模式適用於大量相似物件的建立,而代理模式則更適用於資源密集型或需要控制存取的物件。對於重視程式碼效能的開發者,建議深入理解這些模式的原理和應用場景,並結合專案需求進行技術選型。未來,隨著程式設計正規化的不斷演進,預計會有更多精細化的效能最佳化技術出現,例如更智慧的編譯器最佳化和更底層的硬體加速技術。持續關注這些新興技術,將有助於開發者構建更高效、更穩定的應用程式。