OOP vs SD
https://ithelp.ithome.com.tw/m/questions/10211504
物件導向設計 (OOD) 通常是比結構化設計 (SD) 更好的選擇。物件導向設計是一種軟體設計方法,它強調將系統分解為可重用的、相互協作的物件。這使得軟體更易於理解、擴展和維護。
現在RD的分工都很細,在開發或維護大型系統(或應用程式)的過程中,每個人可能只負責一個小部分功能,而且需求經常會因應市場環境(或老闆的喜好)不斷的變更(甚至變更到發布的前一天晚上還在變更),如果沒有用物件導向的方式來組織各個模組,那在工作的協同上勢必會遇到一大堆bug。
抽象化的過程是讓程式碼更貼近人的思維,並不會讓程式碼變複雜,反而是變得更容易理解且更好維護才是,如果你的物件導向會讓你的程式碼變複雜,那應該好好思考一下你寫的code真的是物件導向嗎?
物件導向的設計還會使效能下降 為甚麼這樣說
- 封裝與間接層 (Indirection)
在物件導向裡,資料和行為綁在一起,所以往往需要多一層方法呼叫。
例如:
order.Total = order.CalculateTotal();
在結構化設計可能就是一個函式呼叫 CalculateTotal(order),但在 OOP,這可能進到 Order 類別 → 呼叫 Strategy → Discount → 再回傳結果。
效能影響:多了層層呼叫(method calls / indirection),比單一函式直呼更慢。
- 多型 (Polymorphism) 與虛擬呼叫
OOP 很常用 介面/繼承 來解耦。
IPricingStrategy strategy = new MemberDiscountStrategy();
var total = strategy.Calculate(order);
在執行時,.NET CLR 或 JVM 需要透過 vtable (虛擬方法表) 去查找哪個方法要被呼叫。相較於一般的靜態函式呼叫,這個 動態繫結 (dynamic dispatch) 會多一步查表的成本。
- 物件的記憶體配置與存取
結構化設計:通常是 連續的資料結構 (struct/array),CPU 快取友善。
struct Order { int price; int qty; };
Order orders[1000]; // memory is continuous
物件導向:每個物件是獨立配置在 Heap,裡面還可能有指標指向別的物件。
存取時會有cache miss(因為資料分散),導致效能下降。
這就是所謂的 「資料取向設計 (Data-Oriented Design, DOD)」對 OOP 的批判。
- 垃圾回收 (GC) 與額外負擔
在物件導向系統裡,大量 new 出來的物件,容易產生 GC 壓力。
特別是短命週期的小物件(DTO、Wrapper、策略類別),會造成頻繁的記憶體配置與釋放。
而在結構化設計(或偏 DOD),你可能只會重複使用陣列或 struct,不需要一直 new 物件。
- 抽象過度 (Over-engineering)
理論上 OOP 不是一定慢,但常見的「設計習慣」會拖垮效能:
每個小邏輯都抽成一個 class。
為了遵守 SOLID 原則加了太多介面。
一個計算流程,可能經過十幾個小物件才跑完。
這些「額外的呼叫層級+物件配置」累積起來,自然比單純的結構化程式慢。
🔄 平衡點
OOP 的效能問題 通常在巨量資料、演算法密集的情境下才會明顯,例如遊戲引擎、金融高頻交易。
在一般商業系統(電商、ERP、Web API),效能瓶頸幾乎都不在 OOP 的額外開銷,而在 資料庫、I/O、網路延遲。
所以大多數時候,我們會選擇 OOP 的維護性,而不是為了省下那幾個 CPU 指令。
結構化設計:像是一條直達的捷運線,快又有效率。
物件導向設計:像是有很多轉車的路網,單趟可能慢一點,但整體更容易擴充、覆蓋更多區域。
台北捷運的設計符合OOP嗎
🚇 1. 結構化設計的角度看捷運
流程導向:
捷運就像是一張大流程圖:
乘客進站 →
刷卡 →
等車 →
上車 →
移動到下一站 →
下車 →
出站。
每個「站」就像一個 步驟模組,乘客(資料)在這些模組之間流轉。
新增需求:如果要加一條線,就要在流程圖上多一串步驟;如果要加環狀線,流程圖會變得很複雜(交錯、轉乘)。
👉 這種看法比較像「結構化設計」。
🧩 2. 物件導向的角度看捷運
如果用 OOP 的角度,捷運可以被拆成「物件 + 責任」:
車站 (Station):擁有自己的名稱、出口、月台資訊,還能處理「乘客進站/出站」的行為。
列車 (Train):擁有車廂數、容量、行駛時間表,負責「載客、行駛」。
路線 (Line):由一組站點組成,知道「哪些車站相連」,能處理「轉乘、行駛規劃」。
乘客 (Passenger):擁有悠遊卡餘額、目的地,會呼叫「搭乘、付費」的行為。
悠遊卡 (EasyCard):封裝餘額、扣款邏輯。
👉 在這裡,每個角色都帶著自己的資料與行為,透過互動完成「搭乘」的流程,而不是由一個大流程去控制一切。這就非常符合 OOP 思維。
⚖️ 對比
結構化設計版捷運:
中央控制室一張大流程圖,乘客只是資料包裹,不會「自己決定」怎麼走。
每加一條新路線,流程圖要重新設計。
物件導向版捷運:
「車站、列車、乘客」各自封裝責任。
要加新路線 = 新增 Line 物件,站點彼此連線即可,不用重寫所有流程。
系統更容易擴充,像是後來台北捷運增加「悠遊卡折扣」、「環狀線」、「空中纜車」,就像加了新類別或新方法。
台北捷運的設計哲學更接近 OOP,因為它是由「站、線、車、人、票卡」這些物件組合而成,每個物件帶著自己的狀態與行為,互相合作完成搭乘流程。但在低階硬體層面,還是保有結構化設計的直覺流程控制。
你說的沒錯:從宏觀來看,我們很多服務設計看似都是 OOP,因為「角色+行為」是人腦自然的建模方式。但在微觀底層,實作仍然需要結構化的流程控制
結構化設計 (C/Pascal style)
int sumEvenSquares(int[] arr, int n) {
int sum = 0;
for (int i = 0; i < n; i++) {
if (arr[i] % 2 == 0) {
sum += arr[i] * arr[i];
}
}
return sum;
}
👉 清楚的流程:for → if → sum。
函數式程式設計 (FP style, C# LINQ)
int sum = arr
.Where(x => x % 2 == 0)
.Select(x => x * x)
.Sum();
👉 沒有明確流程控制,只有「函數組合」:過濾 → 轉換 → 聚合。
OOP:世界是「物件」和「互動」。
SD:世界是「步驟」和「流程」。
FP:世界是「資料」和「轉換」。
這三種都像是 看世界的不同透鏡,可以並存。
像是 C# / Scala / Python 這種語言,其實常常三派混搭。
Functional Programming ≠ Structured Design。
SD 偏向「控制流程」思維,像寫劇本。
FP 偏向「數學函數組合」思維,像代數算式。
兩者雖然都不是 OOP,但站在完全不同的哲學立場。
真實世界複雜
有些地方需要「流程拆解」(像硬體控制、演算法)。
有些地方需要「角色分工」(像業務邏輯、微服務)。
有些地方需要「資料轉換」(像資料處理、串流計算)。
程式語言進化
C#、Java、Python 其實同時支援 OOP、FP、SD。
你可以在 C# 裡一邊寫 LINQ(FP風格),一邊用 class/DI(OOP),還可以在底層用 struct + unsafe code(SD/DOD)。
軟體工程的取捨
效能/貼近硬體 → 結構化(甚至資料導向 DOD)。
可讀性/維護性 → OOP。
高階資料處理/分散式 → FP。
結構化設計 (SD)
訂單總價的演算法(for 迴圈、加總)。
金流 SDK 與驅動層(流程固定,狀態少)。
物件導向 (OOP)
Order, Product, Customer 物件,封裝狀態與行為。
Service 層(PaymentService, PromotionService)。
函數式程式設計 (FP)
大量使用 LINQ/Stream 處理訂單清單:
var vipOrders = orders
.Where(o => o.Customer.IsVIP)
.Select(o => o.Total)
.Sum();
Event sourcing、資料流(Kafka、Rx.NET)→ 全是函數組合思維。
不是要選 OOP 還是 FP 還是 SD,而是學會在對的層次選用對的思維模型。
這也是為什麼現代語言都在「多範式 (multi-paradigm)」發展,因為真實世界需要混搭。
多數語言表達能力不足 不能描述FP中出現的概念
- 學習門檻高,開發人員難找,增加很多的營運成本。
- 記憶體控管在一些情境下,仍然希望能夠更加精確的控制。
- 使用數學體系所建立的抽象概念,所帶來的效益通常並不直觀可見。
雖然種種因素讓FP沒成爲(也幾乎不可能成為)主流,但我還是很鼓勵開發者去學Haskell這種 pure FP 語言。即使開發情境或使用的語言不相同,但會改變自己撰寫程式風格與表達。學習的過程中也很有啟發性,增添了不同維度的選擇。
scottsu360
02/24/25
1.整套 FP 邏輯用起來不夠直覺
2.跟電腦底層邏輯也不ㄧ樣
3.在知道原理情況下 OOP 也能最小化 Side affects,而且OOP 還能配合系統設計、Design patterns
其實 FP 難度不高,難的是用 pure FP 實現大型系統



