首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau
百百 BLOG
首頁
學習紀錄
遊戲心得影視Life書單案件檔案
Side Projects委託作品與二創互動實驗場
Kurau

Kurau Blog

「隨心而寫,真真假假,都是我」

一個記錄生活、輸出興趣的個人空間。
遊戲、影視、閱讀、學習……每一段體驗都值得留下文字。

頁面導覽

  • 學習紀錄
  • 遊戲心得
  • 影視Life
  • 書單
  • 委託作品與二創
  • Kurau
  • 合作邀請

找到我

歡迎來 Discord 找我聊天!

“曾經發生的事不可能忘記,只是暫時想不起來而已。”-《神隱少女》

© 2026 Kurau All rights reserved

軟體工程

物件導向設計(OOD Object-Oriented Design)

By Kurau·2023-02-07·Updated 2026-05-09·4 分鐘閱讀

物件導向設計(OOD, Object-Oriented Design)

TL;DR
OOD 把 OOA 的「世界觀」轉成「設計藍圖」:具體類別關係、介面、設計模式、時序圖。做完 OOD 才開始寫 code。OOD 階段套用 SOLID 跟 設計模式(GoF 23 種)。

OOD 是做什麼

OOA(分析:有什麼)→ ==OOD(設計:怎麼組合)== → OOP(實作:怎麼寫)
                       ↑
                  本篇講這個

OOA 給你 entity 模型,OOD 把它轉成 可實作的設計:

  • 介面定義(API contract)
  • 類別繼承 / 組合 結構
  • 模組依賴 關係
  • 設計模式 套用
  • 時序圖 描述執行流程

結果是一份 design document + UML,工程師看了能直接寫 code。


設計步驟

1. 描述類別 / 介面間的依賴關係

(OOA 結果)              (OOD 加工後)
                         ┌─────────────┐
   User ─→ Cart  ───→    │ IUserService │ ←── UserController
                         └─────────────┘
                                ↑
                         ┌─────────────┐
                         │ UserService  │ ── depends on ─→ UserRepository
                         └─────────────┘

關鍵:OOA 的「User 跟 Cart 有關係」抽象,OOD 變成「User 透過 IUserService 操作 Cart」具體。

2. 套用設計模式

知名 GoF 23 種(部分常用):

Pattern用途範例
Singleton全域只有一個 instanceDB 連線、config
Factory創建物件 by type多種 Notification 子類
Strategy換實作不換介面多種付款方式
Observerpub-sub 通知事件系統
Decorator動態加功能middleware
Adapter橋接不同 API整合舊系統
// Strategy pattern 範例
interface PaymentStrategy {
  process(amount: number): Promise<PaymentResult>;
}

class StripeStrategy implements PaymentStrategy { /* ... */ }
class PayPalStrategy implements PaymentStrategy { /* ... */ }
class LinePayStrategy implements PaymentStrategy { /* ... */ }

class Checkout {
  constructor(private strategy: PaymentStrategy) {}
  pay(amount: number) {
    return this.strategy.process(amount);   // ⭐ 不知道實際是哪一家
  }
}
typescript

3. 定義系統向方法(method)

每個類別 / 介面該暴露什麼 API:

interface IUserService {
  register(input: RegisterInput): Promise<User>;
  login(email: string, password: string): Promise<Session>;
  getCurrentUser(): Promise<User | null>;
  updateProfile(updates: Partial<User>): Promise<User>;
}
typescript

介面是 contract,把「要做什麼」(this layer)跟「怎麼做」(impl layer)分離。

4. 用時序圖描述執行流程

User                Browser            Server          DB
  │                    │                 │              │
  │── 點 Login ──────→ │                 │              │
  │                    │── POST /login ─→ │              │
  │                    │                 │── SELECT ───→ │
  │                    │                 │←── user ────│
  │                    │                 │              │
  │                    │                 │── set cookie│
  │                    │←── 200 OK ──────│              │
  │←── redirect ──────│                 │              │

時序圖讓 frontend / backend 對齊,知道每個 API 的時序、誰先誰後。


OOD 階段必做

1. 套用 SOLID

OOD 的核心方針:

  • SRP — 一個類別只做一件事
  • OCP — 開放擴充、封閉修改
  • LSP — 子類能取代父類
  • ISP — 介面細分,不要塞太多
  • DIP — 依賴抽象不依賴實作

2. 識別 Boundaries

哪些東西該分模組?哪些該放同個 module?
✅ 高內聚:相關功能放一起(User 操作 → UserService 內)
✅ 低耦合:模組間透過介面互動(UserService 不直接動 DB)

3. 設計 錯誤處理 流程

OOA 不太談錯誤,但 OOD 要:

  • 哪些方法會 throw?
  • 用 Result type 還是 exception?
  • 失敗時誰負責 retry / log / 通知?

範例:電商付款流程的 OOD

OOA 給的:User, Order, Payment, Merchant, Inventory

OOD 加工:

// 介面層(抽象)
interface IPaymentGateway {
  charge(amount: number, token: string): Promise<ChargeResult>;
}

interface IInventoryService {
  reserve(productId: string, quantity: number): Promise<Reservation>;
  release(reservationId: string): Promise<void>;
  commit(reservationId: string): Promise<void>;
}

// 服務層(實作)
class CheckoutService {
  constructor(
    private payment: IPaymentGateway,
    private inventory: IInventoryService,
    private orderRepo: OrderRepository,
  ) {}

  async place(input: PlaceOrderInput): Promise<Order> {
    // 1. 預扣庫存
    const reservations = await Promise.all(
      input.items.map((it) => this.inventory.reserve(it.productId, it.quantity))
    );

    try {
      // 2. 收款
      const charge = await this.payment.charge(input.total, input.paymentToken);
      if (!charge.success) throw new PaymentFailed(charge.errorCode);

      // 3. 確認庫存
      await Promise.all(reservations.map((r) => this.inventory.commit(r.id)));

      // 4. 建立訂單
      const order = await this.orderRepo.create({ ...input, paymentId: charge.id });
      return order;

    } catch (err) {
      // 失敗 → 釋放預扣庫存
      await Promise.all(reservations.map((r) => this.inventory.release(r.id)));
      throw err;
    }
  }
}
typescript

這就是 OOD 的具體產出:介面、依賴、流程、錯誤處理都明確。


現代視角:Clean Architecture

2026 年 OOD 常跟 Clean Architecture 結合:

┌─────────────────────────────────────┐
│  Frameworks(Express / Next.js / DB) │  最外層,最易變
├─────────────────────────────────────┤
│  Interface Adapters(Controllers)    │
├─────────────────────────────────────┤
│  Use Cases(CheckoutService)          │  ← 我們在 OOD 設計這層
├─────────────────────────────────────┤
│  Entities(User / Order / Product)    │  ← OOA 的核心
└─────────────────────────────────────┘
        依賴方向 →(內層不能依賴外層)

核心原則:依賴方向 永遠由外向內。Entity 不知道有 framework,Use Case 不知道有 DB。


OOD 給前端工程師的啟發

前端也該做 OOD,只是規模小:

// component 層級的 OOD
interface IPostListProps {
  posts: Post[];
  onSelect: (post: Post) => void;
}

interface IPostListBehavior {
  filter(query: string): void;
  sort(by: 'date' | 'title'): void;
}

// 組件
function PostList({ posts, onSelect }: IPostListProps) { /* ... */ }

// hook(behavior)
function usePostListBehavior(initial: Post[]): IPostListBehavior & { posts: Post[] } { /* ... */ }
typescript

介面分離 props vs behavior 讓 component 跟資料邏輯解耦,容易測試。

目錄

    ◆ 相關文章

    • 物件導向分析(OOA Object-Oriented Analysis)

      2026-05-09
    • 物件導向程式設計基本原則 - SOLID

      2026-05-09
    • Memory Leak (記憶體管理)

      2026-05-09
    • 四種渲染模式

      2026-05-09
    ← 上一篇發布自己的npm包下一篇 →物件導向分析(OOA Object-Oriented Analysis)

    ◆ 關於作者

    Kurau

    個人寫作 / 創作的 SoT,記錄遊戲、影視、學習與生活。

    更多 Kurau 的文章