[心得整理] c# 物件導向程式 - 9.OCP 開放封閉原則
前言
介紹來到最後一個原則,也是最最最重要的OCP 開放封閉原則
之前學習的五大原則的實踐在寫程式上面
就是達到讓程式可以物件導向的境界
開放封閉原則 - 現實生活面
要用於現實生活中,可以換頭的電動螺絲起子就是最好的範例
開放工具頭可以抽換,封閉主體的馬達架構
開放封閉原則 - 程式面
開放功能可抽換,封閉架構被修改
寫程式的時候最常遇到功能修改
原本要A改B換C,上線後又說還是要A
但老闆覺得C也不錯,可以後台做的開關讓user切換嗎之類的
(想像一下原本螺絲起子情況 本來說要十字,後來改要一字,最後說能不能兩個都要)
如果功能是可以被抽換的這樣是不是就比較不會令人討厭呢
用購物車運費的案例來說好了
參考91的[30天快速上手TDD][Day 9]Refactoring legacy code 簡介
各貨運公司的運費都不一樣,如何把算運費的功能設計為可抽換
先來看一下最直覺的寫法
int shippingFee = 0;
int piecesRate = 0;
if (shippingComapanyName == "黑貓")
{
piecesRate = 150;
shippingFee = pieces * piecesRate;
}
else if (shippingComapanyName == "白貓")
{
piecesRate = 130;
shippingFee = pieces * piecesRate;
if (shippingFee > 500)
{
shippingFee -= 50;
}
}
這樣個程式碼就要不停的維護這if
這時候應該把之前介紹的原則拿出來運用
SRP 單一職責
算運費應該是每間貨運公司都不同
應該有貨運公司有自己算運費的規則
要有貨物公司 class
DIP 依賴反轉
要有介面(抽象) 這樣才能抽換貨運公司
建立一個貨運公司介面
ISP 介面隔離
算運費是每間貨運都會有的功能
所以要在貨運公司介面
設計一個算運費功能
當然在開發過程也要注意
LSP 里氏替換 - 繼承的時候要考慮到子類別要可以替代父類別
LKP 最少知識 - 不要把流程複雜化
來看一下程式碼
//介面
public interface IShippable
{
void FeeCalculate(int pieces);
int GetFee();
}
//白貓貨運公司
public class WhiteCat:IShippable
{
private int _shippingFee;
public void FeeCalculate(int pieces)
{
int piecesRate = 130;
this._shippingFee = pieces * piecesRate;
if (this._shippingFee > 500)
{
this._shippingFee -= 50;
}
}
public int GetFee()
{
return this._shippingFee;
}
}
黑貓貨運的class 請自己腦補一下
目前我們有了介面和class
在取運費的時候要如何能夠把IF拿掉呢
還記得DIP有提到IoC嗎,我們應該讓別人幫我new 貨運公司
就像這樣
public class ShippingCompanyFactory
{
public static IShippable GetShippingCompany(string shippingCompanyName)
{
switch (shippingCompanyName)
{
case "BlackCat":
return new BlackCat();
case "WhiteCat":
return new WhiteCat();
}
}
}
最後來看一下主程式
IShippable shippingCompany =
ShippingCompanyFactory.GetShippingCompany("白貓");
shippingCompany.FeeCalculate(pieces);
shippingFee = shippingCompany.GetFee();
之後要加入新貨運公司的時候,就去新增貨物公司的class
再去 ShippingCompanyFactory 加入
基本上主流程式是不需要改變的
OCP 開放封閉原則,就是要讓程式說話
主要流程不應該出現細節與邏輯
補充
實作上 原本寫死的變數 變成用參數傳進來 這樣也算是OCP的一種 現在不用改這class的程式碼 只要改變呼叫端的變數 對吧
public void Exec() { Console.WriteLine("FixString") } => public void Exec(string msg) { Console.WriteLine(msg) }
繼承也可 父類別virtual 子類別在override 不過 這樣很容易 改太大或是改成完全不相關 不是很建議
結語
終於把OCP寫完了,SOLID原則還沒結束,還會有一篇整理更多網路上的資源
推薦閱讀
[ASP.NET]91之ASP.NET由淺入深 不負責講座 Day18 - 開放封閉原則
亂談軟體設計(2):Open-Closed Principle
如果內容有誤請多鞭策謝謝