使用基類模型(class model)優化代碼:從零到掌握 DRY 原則

更新日期: 2024 年 12 月 26 日

在開發過程中,重複代碼會增加維護成本,降低可讀性和擴展性。

通過基類模型(class model)或工具類的抽象化設計,我們可以將重複邏輯集中管理,實現代碼的高效重用。

這篇文章將帶你學習如何使用基類模型優化圖片處理邏輯,並實現符合 DRY (Don’t Repeat Yourself) 原則的代碼結構。


問題背景

目前,在項目中的多個模型(如 Profile 和其他圖片相關模型)存在一些重複邏輯,例如:

  • 圖片的 WebP 格式轉換與上傳到 S3。
  • 原始文件的清理和管理。

這些重複代碼會導致維護成本上升,尤其當邏輯需要更新時,開發者需要在多處修改代碼,增加出錯風險。

解決方案是將這些邏輯抽象到一個通用的基類模型中,讓模型專注於自身業務邏輯,而通用功能交給基類處理。


創建通用的基類模型

為了解決上述問題,我們設計了一個名為 WebPImageModelMixin 的基類,用於管理圖片的 WebP 處理與 S3 文件管理邏輯。

mixins.py

from django.db import models
from utils.image_processing import convert_and_upload_to_webp
import boto3
from django.conf import settings

class WebPImageModelMixin(models.Model):
    """
    用於將圖片轉換為 WebP 格式並上傳到 S3 的基類
    """

    class Meta:
        abstract = True

    def process_and_upload_image(self, image_file, folder_name):
        """
        將圖片轉換為 WebP 格式並上傳到 S3,同時清理原始圖片。

        參數:
        - image_file: 要處理的圖片檔案
        - folder_name: S3 存儲文件夾名稱

        返回:
        - 處理後圖片的 S3 路徑
        """
        original_filename = image_file.name
        new_image_path = convert_and_upload_to_webp(image_file, folder_name)
        image_file.name = new_image_path

        # 從 S3 中刪除原始文件
        if original_filename:
            s3 = boto3.client("s3", region_name=settings.AWS_S3_REGION_NAME)
            s3.delete_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=original_filename)

這段代碼提供了以下功能:

  1. 將圖片轉換為 WebP 格式。
  2. 將新圖片上傳到 S3。
  3. 自動清理原始文件。

應用方式:以基類邏輯更新模型

在設計好基類後,我們可以讓需要圖片處理功能的模型(如 ProfileServiceImage)繼承基類 WebPImageModelMixin,以實現代碼邏輯的集中管理。

Profile 模型示例

以下是修改後的 Profile 模型代碼,它繼承了基類並應用了通用邏輯:

from django.contrib.auth.models import User
from django.db import models
from mixins import WebPImageModelMixin

class Profile(WebPImageModelMixin, models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
    photo = models.ImageField(upload_to="profile_photos/", blank=True, null=True)
    bio = models.TextField(max_length=200, null=True)
    location = models.CharField(max_length=50, null=True)
    is_client = models.BooleanField(default=True, null=True)
    is_freelancer = models.BooleanField(default=False, null=True)
    freelancer_verified = models.BooleanField(default=False, null=True)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if self.photo:
            self.process_and_upload_image(self.photo, "profile_photos/")

    def __str__(self):
        return f"{self.user.username}'s Profile"

save 方法中,圖片的處理和上傳交由基類方法 process_and_upload_image 完成,避免了冗餘的代碼。


設計優化的好處

更乾淨的代碼

模型只需關注核心功能,例如字段定義與業務邏輯,圖片的處理與 S3 文件管理的細節由基類處理。

更高的重用性

任何需要圖片處理的模型,只需繼承 WebPImageModelMixin,並在適當的位置調用基類方法即可實現同樣的功能。

更好的維護性

當圖片處理邏輯需要修改時,只需在基類中進行更新,所有繼承基類的模型都會自動同步改動,減少了重複修改的工作量。


總結

通過將圖片的處理邏輯抽象到通用的基類模型中,我們實現了代碼的高效重用,符合 DRY 原則的最佳實踐。

不僅提升了代碼的可讀性和維護性,還大幅度減少了重複邏輯的出現。

現在,你可以將這一方法應用到你的項目中,為每一個需要圖片處理的模型提供統一的解決方案,提升開發效率!

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *