← Back to list

Python MVC 架構淺顯易懂解析:讓程式設計變得更有條理!

在程式開發的世界裡,「架構」就像是建築藍圖,決定了程式如何運作、如何組織、如何維護。如果沒有良好的架構,程式碼就可能變得混亂不堪,難以修改和擴展。

AaronL · 2025-03-03 13:13 · 0 claps · 17.9 min read
#mvc #網頁開發 #軟體架構 #軟體開發 #程式設計
Open on Medium ↗
Wiki topics: STP · Startups & Venture

Python MVC 架構淺顯易懂解析:讓程式設計變得更有條理!

在程式開發的世界裡,「架構」就像是建築藍圖,決定了程式如何運作、如何組織、如何維護。如果沒有良好的架構,程式碼就可能變得混亂不堪,難以修改和擴展。

「MVC 架構」就成了一個清晰、易管理的開發方式,幫助我們把程式的各個部分分門別類,讓開發變得更加直觀!那麼,MVC 到底是什麼呢?讓我們用最簡單的方式來理解它吧!

MVC 是什麼?用「餐廳」來解釋!

MVC 是Model(模型)、View(視圖)、Controller(控制器)的縮寫,它是一種設計模式,幫助我們把程式拆分成不同的角色,讓各部分各司其職。為了讓概念更清楚,我們用「餐廳」來舉例:

  • Model(模型) → 廚房 Model 負責處理「資料」,就像廚房負責準備食材並烹煮食物。當顧客點餐時,廚房(Model)會根據菜單來準備相應的食物(資料處理)。
  • View(視圖) → 餐廳座位區 View 負責「顯示結果」,就像餐廳座位區負責把食物(資料)呈現給客人。當 Model 準備好餐點,View 就會決定如何擺盤,讓顧客(使用者)能夠看到、享用美味的餐點(資料呈現)。
  • Controller(控制器) → 服務生 Controller 是溝通橋樑,負責處理用戶的請求並傳達給 Model 和 View,就像餐廳裡的服務生。顧客點餐(用戶輸入)後,服務生(Controller)會將訂單送到廚房(Model),等餐點準備好後,再通知餐廳座位區(View)來擺放餐點。

這樣一來,餐廳的運作變得井然有序,就像我們在寫程式時,MVC 幫助我們讓程式碼更有結構、更易維護!

MVC 是什麼?用「餐廳」來解釋!

MVC 是什麼?用「餐廳」來解釋!

為什麼要使用 MVC?

採用 MVC 模式有很多好處,以下是最重要的幾點:

分工明確,方便維護 — — 讓程式的資料處理、介面顯示、邏輯控制各自獨立,未來修改或擴充時不會牽一髮而動全身。 ✅ 程式碼更清楚,可讀性更高 — — 不會把資料處理、顯示和邏輯全部混在一起,使開發更直觀。 ✅ 多人開發更順利 — — 前端設計師可以專注在 View,後端工程師可以專注在 Model,開發過程更流暢。 ✅ 可擴展性強 — — 想要更換顯示介面?只要改 View 即可,Model 和 Controller 不用動!

如何在 Python 中實作 MVC?

在 Python 開發中,MVC 可以應用於多種框架,例如:

  1. Flask / Django(Web 開發) — — 用於開發網站應用程式
  2. Tkinter(桌面應用) — — 用於 GUI 應用程式

舉個最簡單的 MVC 例子,我們用 Flask 來實作一個「待辦事項清單」應用:

from flask import Flask, render_template

app = Flask(__name__)

# Model(數據處理層)
tasks = ["買牛奶", "寫報告", "去健身房"]

# View(顯示層)
@app.route("/")
def home():
    return render_template("index.html", tasks=tasks)

# Controller(控制器層)
@app.route("/add/<task>")
def add_task(task):
    tasks.append(task)
    return f"已新增:{task}"

if __name__ == "__main__":
    app.run(debug=True)

這段程式碼的運作方式如下:

  • Model(tasks) 儲存待辦事項列表
  • View(home 函式 + index.html) 顯示待辦事項
  • Controller(add_task) 負責處理新增待辦事項的請求

這樣的設計,讓我們的程式碼變得清楚易讀、易於擴展

MVC 在現實世界的應用

MVC 不只是在開發應用程式時有用,它幾乎適用於所有需要組織架構的系統,包括:

🔹 電子商務網站 — — 商品資訊(Model)、使用者介面(View)、購物車管理(Controller) 🔹 遊戲開發 — — 遊戲數據(Model)、畫面渲染(View)、玩家操作(Controller) 🔹 手機應用程式 — — 資料儲存(Model)、UI 介面(View)、用戶互動(Controller)

MVC 架構就像是程式的「大腦」,讓開發變得更加順暢!

使用 Python 和 Tkinter 建立密碼管理器

在這篇教學中,我們將使用 Python 和 Tkinter 建立一個簡單的密碼管理器。這個密碼管理器可以生成隨機密碼、儲存密碼、檢查密碼強度,並提醒用戶更新過期的密碼。

目標

  1. 使用MVC結構來建立一個圖形用戶界面 (GUI) 來管理密碼。
  2. 生成隨機密碼並自動複製到剪貼簿。
  3. 儲存密碼到本地 JSON 文件。
  4. 檢查密碼強度並顯示在界面上。
  5. 提醒用戶更新過期的密碼。

MVC結構來建立一個圖形用戶界面 (GUI) 來管理密碼

MVC結構來建立一個圖形用戶界面 (GUI) 來管理密碼

1. 安裝所需的庫

首先,我們需要安裝所需的庫。這個專案需要 tkinter 和 pyperclip 庫。tkinter 是 Python 的標準 GUI 庫,而 pyperclip 用於複製文本到剪貼簿。

pip install pyperclip

2. 建立密碼管理器的控制器

我們將建立一個 PasswordManagerController 類來處理密碼的生成、儲存和檢索。

from random import choice, randint, shuffle
import pyperclip
from tkinter import messagebox
import json
import os
from datetime import datetime

class PasswordManagerController:
    """負責密碼產生與檢索的 Controller 層"""

    def __init__(self):
        """初始化"""
        self.data_file = "data.json"

    def save_to_file(self, data, filename="data.json"):
        """將資料寫入 JSON"""
        with open(filename, "w") as file:
            json.dump(data, file, indent=4)

    def load_from_file(self):
        try:
            with open(self.data_file, "r") as file:
                return json.load(file)
        except (json.JSONDecodeError, FileNotFoundError):
            # 處理文件不存在或無效 JSON 格式的情況
            messagebox.showerror(title="錯誤", message="無法讀取資料檔案。")
            return {}

    @staticmethod
    def generate_password():
        """產生隨機密碼"""
        letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
        numbers = '0123456789'
        symbols = '!#$%&()*+'

        password_list = [
            choice(letters) for _ in range(randint(8, 10))
        ] + [
            choice(symbols) for _ in range(randint(2, 4))
        ] + [
            choice(numbers) for _ in range(randint(2, 4))
        ]

        shuffle(password_list)
        password = "".join(password_list)
        pyperclip.copy(password)  # 自動複製密碼到剪貼簿
        return password

    @staticmethod
    def save_password(website, email, password):
        """儲存密碼,並提供錯誤處理"""
        if not website or not email or not password:
            messagebox.showerror(title="錯誤", message="請填寫所有欄位!")
            return False

        # 創建 PasswordManagerController 類的實例
        controller = PasswordManagerController()

        # 使用實例方法來呼叫 load_from_file 和 save_to_file
        data = controller.load_from_file()
        data[website] = {
            "email": email,
            "password": password,
            "timestamp": datetime.now().isoformat()
        }
        controller.save_to_file(data)

        messagebox.showinfo(title="成功", message="密碼已儲存!")
        return True

    @staticmethod
    def search_password(website):
        """搜尋密碼"""
        if not website:
            return None
        controller = PasswordManagerController()
        data = controller.load_from_file()
        return data.get(website, None)

    @staticmethod
    def check_password_strength(password):
        """檢查密碼強度"""
        if len(password) < 8:
            return "弱"
        elif len(password) < 12:
            return "中"
        elif any(char.isdigit() for char in password) and any(char.isalpha() for char in password) and any(char in '!#$%&()*+' for char in password):
            return "強"
        else:
            return "中"

3. 建立密碼管理器的視圖

我們將建立一個 PasswordManagerView 類來處理圖形用戶界面 (GUI)。

from tkinter import *
from tkinter import messagebox
from controller import PasswordManagerController
from datetime import datetime, timedelta

class PasswordManagerView:
    def __init__(self):
        self.window = Tk()
        self.window.title("Password Manager")
        self.window.config(padx=50, pady=50)

        # 設定 column 1 & column 2 可調整大小
        self.window.columnconfigure(1, weight=1)
        self.window.columnconfigure(2, weight=1)

        # 建立 Canvas 並放置圖片
        self.canvas = Canvas(width=200, height=200)
        self.logo_img = PhotoImage(file="logo.png")
        self.canvas.create_image(100, 100, image=self.logo_img)
        self.canvas.grid(row=0, column=1)

        # Label: 網站
        self.website_label = Label(text="Website:")
        self.website_label.grid(row=1, column=0, sticky="E")

        # Label: Email/Username
        self.email_label = Label(text="Email/Username:")
        self.email_label.grid(row=2, column=0, sticky="E")

        # Label: Password
        self.password_label = Label(text="Password:")
        self.password_label.grid(row=3, column=0, sticky="E")

        # 輸入框: 網站
        self.website_entry = Entry(width=33, justify=CENTER)
        self.website_entry.grid(row=1, column=1, sticky="EW")
        self.website_entry.focus()

        # 按鈕: 搜尋
        self.search_button = Button(text="Search", width=14, command=self.search)
        self.search_button.grid(row=1, column=2, sticky="EW")

        # 輸入框: Email(可預設常用 Email)
        self.email_entry = Entry(width=35, justify=CENTER)
        self.email_entry.grid(row=2, column=1, columnspan=2, sticky="EW")
        self.email_entry.insert(0, "example@example.com")  # 預設 Email

        # 輸入框: 密碼
        self.password_entry = Entry(width=21, justify=CENTER)
        self.password_entry.grid(row=3, column=1, sticky="EW")
        self.password_entry.bind("<KeyRelease>", self.update_password_strength)

        # Label: 密碼強度
        self.strength_label = Label(text="Strength: ")
        self.strength_label.grid(row=4, column=0, sticky="E")

        # Label: 過期狀態
        self.expiry_label = Label(text="")
        self.expiry_label.grid(row=5, column=0, columnspan=3, sticky="EW")

        # 按鈕: 產生密碼
        self.gen_pwd_button = Button(text="Generate Password", command=self.generate)
        self.gen_pwd_button.grid(row=3, column=2, sticky="EW")

        # 按鈕: 儲存
        self.save_button = Button(text="Add", width=36, command=self.save)
        self.save_button.grid(row=6, column=1, columnspan=2, sticky="EW")

        self.check_password_expiry()

        self.window.mainloop()

    def generate(self):
        """產生隨機密碼並填入輸入框"""
        password = PasswordManagerController.generate_password()
        self.password_entry.delete(0, END)
        self.password_entry.insert(0, password)
        self.update_password_strength()

    def save(self):
        """儲存密碼,並在成功後清除相關欄位"""
        website = self.website_entry.get().strip()
        email = self.email_entry.get().strip()
        password = self.password_entry.get().strip()

        print(f"[DEBUG] save() -> website: {website}, email: {email}, password: {password}")  # Debug

        if PasswordManagerController.save_password(website, email, password):
            # 儲存成功後清空網站和密碼欄位
            self.website_entry.delete(0, END)
            self.password_entry.delete(0, END)
            self.update_password_strength()
            self.check_password_expiry()

    def search(self):
        """搜尋密碼,若找到則填入對應欄位"""
        website = self.website_entry.get().strip()
        print(f"[DEBUG] search() -> website: {website}")  # Debug
        result = PasswordManagerController.search_password(website)
        if result:
            self.email_entry.delete(0, END)
            self.email_entry.insert(0, result["email"])
            self.password_entry.delete(0, END)
            self.password_entry.insert(0, result["password"])
            self.update_password_strength()
            messagebox.showinfo(title=website, message=f"Email: {result['email']}\nPassword: {result['password']}")
        else:
            messagebox.showerror(title="錯誤", message="找不到該網站的紀錄!")

    def update_password_strength(self, event=None):
        """更新密碼強度標籤"""
        password = self.password_entry.get().strip()
        strength = PasswordManagerController.check_password_strength(password)
        self.strength_label.config(text=f"Strength: {strength}")

    def check_password_expiry(self):
        """檢查密碼是否過期"""
        controller = PasswordManagerController()
        data = controller.load_from_file()
        now = datetime.now()
        expired_passwords = []

        for website, details in data.items():
            timestamp = details.get("timestamp")
            if timestamp:
                timestamp = datetime.fromisoformat(timestamp)
                if now - timestamp > timedelta(days=1):
                    expired_passwords.append((website, details["email"]))

        if expired_passwords:
            expired_sites = ", ".join([website for website, _ in expired_passwords])
            self.expiry_label.config(text=f"以下網站的密碼已過期超過一天,請更新密碼:{expired_sites}")
        else:
            self.expiry_label.config(text="")

4. 建立主程式

我們將建立一個主程式來啟動密碼管理器。

from view import PasswordManagerView

if __name__ == "__main__":
    PasswordManagerView()

5. 建立 JSON 文件

確保在專案目錄中有一個名為 data.json 的文件,初始內容為空字典:

{}

6. 執行程式

確保所有文件都在正確的目錄結構中:

Password Manager/
├── controller.py
├── main.py
├── view.py
└── data.json

然後執行主程式:

python main.py

總結

通過這些步驟,我們建立了一個簡單的密碼管理器。這個密碼管理器可以生成隨機密碼、儲存密碼、檢查密碼強度,並提醒用戶更新過期的密碼。希望這篇教學文章對你有幫助!如果還有其他問題,請隨時告訴我。

結論:MVC 讓程式開發更有條理

MVC 是一種簡單卻強大的架構設計,它幫助我們: ✔ 分工清楚,讓程式易讀、易維護開發過程更有組織,讓前後端開發者能夠分工合作擴展性強,未來修改程式時更加容易

無論你是開發 Web、桌面應用還是遊戲,MVC 都是一個值得學習和應用的架構模式。現在,讓我們站在 MVC 的肩膀上,讓程式變得更高效、更有條理吧!


메타데이터
post_id
4f9dc170a8ff
slug
python-mvc-架構淺顯易懂解析-讓程式設計變得更有條理-4f9dc170a8ff
url
https://medium.com/@kenAaa/python-mvc-%E6%9E%B6%E6%A7%8B%E6%B7%BA%E9%A1%AF%E6%98%93%E6%87%82%E8%A7%A3%E6%9E%90-%E8%AE%93%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88%E8%AE%8A%E5%BE%97%E6%9B%B4%E6%9C%89%E6%A2%9D%E7%90%86-4f9dc170a8ff
canonical_url
https://medium.com/@kenAaa/python-mvc-%E6%9E%B6%E6%A7%8B%E6%B7%BA%E9%A1%AF%E6%98%93%E6%87%82%E8%A7%A3%E6%9E%90-%E8%AE%93%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88%E8%AE%8A%E5%BE%97%E6%9B%B4%E6%9C%89%E6%A2%9D%E7%90%86-4f9dc170a8ff
author_url
https://medium.com/@kenAaa
status
ok
fetched_at
2026-09-01 16:14:49