MVC 模式有效分離應用程式關注點,使開發和維護更加便捷。模型負責資料和業務邏輯,檢視負責呈現資料,控制器則協調兩者互動。這種分離使得修改或擴充套件應用程式更加容易,例如新增檢視只需新增對應控制器即可。微服務架構則更進一步,將應用程式拆分為更小的、獨立佈署的服務,提升系統彈性和可擴充套件性。每個微服務專注於單一功能,並透過 API 進行通訊,例如使用 gRPC 實作支付服務,可以獨立佈署和擴充套件支付功能,而不會影響其他服務。
MVC 設計模式:軟體架構的關鍵
MVC(Model-View-Controller)設計模式是軟體開發中一種廣泛使用的架構模式,它透過將應用程式分為三個主要元件來實作鬆耦合和關注點分離。MVC 模式不僅在傳統的桌面應用程式中發揮作用,在現代的 Web 開發框架中也佔有重要地位。
MVC 模式的核心元件
-
模型(Model):模型是 MVC 模式的核心,代表了應用程式的知識和業務邏輯。它包含了資料、狀態和規則的管理,是整個應用程式的骨架。模型負責處理資料的驗證、狀態變更等業務邏輯,並且獨立於使用者介面。
-
檢視(View):檢視是模型的視覺表示,用於向使用者展示資料。它可以是圖形使用者介面(GUI)、文字輸出、PDF 檔案、圖表等各種形式。檢視的主要職責是顯示資料,而不處理資料。
-
控制器(Controller):控制器是模型和檢視之間的橋樑,負責處理使用者的輸入並更新模型和檢視。當使用者與檢視互動時,檢視會通知控制器,控制器再與模型互動,並根據模型的回饋更新檢視。
MVC 模式的工作流程
一個典型的 MVC 應用程式工作流程如下:
- 使用者透過點選按鈕等方式觸發檢視的事件。
- 檢視將使用者的動作通知給控制器。
- 控制器處理使用者的輸入,並與模型互動。
- 模型執行必要的驗證和狀態變更,並通知控制器下一步該怎麼做。
- 控制器指示檢視更新顯示,以反映模型的變更。
為什麼需要控制器?
有人可能會問,為什麼不能直接跳過控制器,讓模型和檢視直接互動?雖然理論上可行,但這樣做會喪失 MVC 的一個重要優勢:能夠在不修改模型的情況下使用多個檢視。為了實作模型和檢視之間的解耦,通常每個檢視都需要自己的控制器。如果模型直接與特定的檢視通訊,將很難實作多個檢視的靈活切換。
實務範例
MVC 模式在現實生活中有很多對應的例子。例如,在建造新房子的過程中,不同的專業人員負責不同的工作,如安裝水電、油漆裝潢等。在餐廳中,服務員接收訂單並將餐點呈給顧客,而廚師則負責烹飪食物。
在 Web 開發領域,許多框架採用了 MVC 模式或其變體。例如,Web2py 和 Django 等 Python 框架都使用了 MVC 的概念。Django 中將控制器稱為「view」,而將檢視稱為「template」,形成了 Model-View-Template(MVT)的架構。
MVC 模式的優點
- 關注點分離:MVC 將應用程式的不同關注點分離開來,使得圖形設計師可以專注於使用者介面的設計,而開發人員則可以專注於業務邏輯的實作,兩者互不幹擾。
- 鬆耦合:由於模型和檢視之間的耦合度很低,因此可以獨立地修改或擴充套件每個部分,而不會影響到其他部分。例如,新增一個新的檢視非常簡單,只需為其實作一個新的控制器即可。
- 易於維護:由於每個元件的職責明確,因此維護工作變得更加容易。
從零實作 MVC
在從零實作 MVC 時,應確保建立出「聰明」的模型、「瘦身」的控制器和「笨拙」的檢視。
- 聰明的模型:
- 包含所有的驗證/業務規則/邏輯
- 處理應用程式的狀態
- 存取應用程式資料(資料函式庫、雲端等)
- 不依賴於使用者介面
- 瘦身的控制器:
- 當使用者與檢視互動時更新模型
- 當模型變更時更新檢視
- 在必要時處理資料並傳遞給模型/檢視
- 不顯示資料
總之,MVC 模式透過將應用程式分解為模型、檢視和控制器三個元件,實作了關注點分離和鬆耦合,從而提高了軟體的可維護性和可擴充套件性。無論是在傳統的桌面應用程式還是在現代的 Web 開發框架中,MVC 都是一種非常有價值的設計模式。
MVC 設計模式詳解與實作
MVC(Model-View-Controller)是一種廣泛使用的軟體架構模式,主要用於將應用程式的邏輯、資料和呈現層分離,以提高程式碼的可維護性和可擴充套件性。
MVC 的基本組成
- Model(模型):負責管理應用程式的資料和業務邏輯。它直接與資料函式庫或其他資料來源互動,並對資料進行處理。
- View(檢視):負責向使用者展示資料。它接收來自控制器的資料,並將其呈現給使用者。
- Controller(控制器):負責協調模型和檢視之間的互動。它接收使用者的輸入,呼叫模型進行資料處理,並將結果傳遞給檢視進行展示。
MVC 的特點
- 分離關注點:MVC 將應用程式的邏輯、資料和呈現層分離,使得各個部分可以獨立開發和維護。
- 提高可維護性:由於各個部分的分離,修改或替換其中一個部分不會影響到其他部分,從而提高了程式碼的可維護性。
- 提高可擴充套件性:MVC 使得新增或修改功能變得更加容易,因為新的功能可以透過新增或修改個別的部分來實作,而不需要對整個應用程式進行大幅度的修改。
實作 MVC 模式
以下是一個簡單的例子,展示如何從零開始實作 MVC 模式。這個例子是一個名為「Quote Printer」的應用程式,使用者可以輸入一個數字,然後看到與該數字相關的名言。
資料定義
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.",
)
模型(Model)
class QuoteModel:
def get_quote(self, n):
try:
value = quotes[n]
except IndexError as err:
value = "Not found!"
return value
檢視(View)
class QuoteTerminalView:
def show(self, quote):
print(f'And the quote is: "{quote}"')
def error(self, msg):
print(f"Error: {msg}")
def select_quote(self):
return input("Which quote number would you like to see? ")
控制器(Controller)
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)
def main():
controller = QuoteTerminalController()
while True:
controller.run()
if __name__ == "__main__":
main()
微服務架構模式
微服務架構是一種將應用程式設計為一組鬆散耦合、協作的服務的架構風格。每個服務都是獨立佈署的,並透過明確定義的 API 進行通訊。
微服務的特點
- 鬆散耦合:每個服務都是獨立的,可以獨立開發、佈署和擴充套件。
- 獨立佈署:每個服務都可以獨立佈署,不需要影響其他服務。
- API 通訊:服務之間透過明確定義的 API 進行通訊。
實務範例
許多知名公司,如 Netflix、Uber 和 Amazon,都採用了微服務架構來處理複雜的業務需求和大規模的使用者請求。
微服務架構模式的應用場景與實作
微服務架構模式提供了多種聰明的解決方案,適用於具有特定特徵的應用程式開發。以下列舉了一些微服務架構模式的典型應用場景:
- 需要支援多種客戶端,包括桌面和行動裝置
- 需要為第三方提供 API 介面
- 需要透過訊息傳遞與其他應用程式進行通訊
- 需要存取資料函式庫、與其他系統進行通訊,並傳回適當的回應格式(JSON、XML、HTML 或 PDF)
- 應用程式具有對應不同功能區域的邏輯元件
使用 gRPC 實作微服務模式:支付服務
在微服務的世界中,從佈署單一應用程式轉變為佈署多個小型服務,意味著需要處理的事務數量呈指數級增長。 Docker 的出現使得事情變得更加簡單,因為我們可以將服務封裝成容器,然後執行這些容器,並確保它們之間可以相互通訊。
定義服務及其方法
首先,我們使用 Protocol Buffers(protobuf)定義服務及其方法,在 ch06/microservices/grpc/payment.proto 檔案中定義了 PaymentService 服務及其方法:
syntax = "proto3";
package payment;
service PaymentService {
rpc ProcessPayment(PaymentRequest) returns (PaymentResponse) {}
}
message PaymentRequest {
string order_id = 1;
double amount = 2;
string currency = 3;
string user_id = 4;
}
message PaymentResponse {
string payment_id = 1;
string status = 2; // 例如 "SUCCESS" 或 "FAILED"
}
編譯 protobuf 檔案
接下來,我們需要使用 protobuf 編譯器(protoc)將 payment.proto 檔案編譯成 Python 程式碼。命令如下:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. payment.proto
這將生成兩個檔案:payment_pb2.py 和 payment_pb2_grpc.py。
實作支付服務邏輯
然後,我們在 payment_service.py 檔案中提供支付服務的邏輯,擴充套件了由 protobuf 編譯器生成的 Python 程式碼:
from concurrent.futures import ThreadPoolExecutor
import grpc
import payment_pb2
import payment_pb2_grpc
class PaymentServiceImpl(payment_pb2_grpc.PaymentServiceServicer):
def ProcessPayment(self, request, context):
return payment_pb2.PaymentResponse(payment_id="12345", status="SUCCESS")
def main():
print("Payment Processing Service ready!")
server = grpc.server(ThreadPoolExecutor(max_workers=10))
payment_pb2_grpc.add_PaymentServiceServicer_to_server(PaymentServiceImpl(), server)
server.add_insecure_port("[::]:50051")
server.start()
server.wait_for_termination()
編寫測試客戶端
最後,我們編寫一個測試客戶端,以測試支付服務:
import grpc
import payment_pb2
import payment_pb2_grpc
with grpc.insecure_channel("localhost:50051") as chan:
stub = payment_pb2_grpc.PaymentServiceStub(chan)
resp = stub.ProcessPayment(payment_pb2.PaymentRequest(order_id="order123", amount=100.0, currency="USD", user_id="user123"))
print(resp)
程式碼解密:
- 定義服務及其方法:使用 protobuf 定義
PaymentService服務及其ProcessPayment方法。 - 編譯 protobuf 檔案:使用 protoc 編譯器將
payment.proto檔案編譯成 Python 程式碼。 - 實作支付服務邏輯:在
payment_service.py檔案中提供支付服務的邏輯,擴充套件了由 protobuf 編譯器生成的 Python 程式碼。 - 編寫測試客戶端:編寫一個測試客戶端,以測試支付服務。
此圖示顯示了微服務架構模式的應用場景與實作:
graph LR;
A[客戶端] -->|gRPC| B[支付服務];
B -->|處理支付| C[資料函式庫];
C -->|傳回結果| B;
B -->|傳回結果| A;
**圖表翻譯:**此圖表顯示了客戶端透過 gRPC 與支付服務進行通訊,支付服務處理支付請求並存取資料函式庫,最終傳回結果給客戶端。