S.O.L.I.D 物件導向設計原則 - OCP (Open-Closed Principle)

Posted by Ryan Tseng on 2017-10-10

對修改封閉,對擴充開放

接下來講到第二個物件導向的設計原則 OCP 或稱為 開閉原則,以往我們在幫系統加上 Log 的時候,會有檔案類型的Log、資料庫類型Log、甚至只是單純在Debug時呈現在Console的Log。

這些都是儲存 Log 的方式,可是我們要怎麼樣在程式裡面完成這件事情,以下請看第一個例子

第一個例子

1
2
3
4
5
6
7
8
9
10
11
12
public class Logger
{
public void ConsoleLog(string message)
{
// 實作顯示 Log 至 Console
}

public void FileLog(string message)
{
// 實作儲存 Log 至檔案
}
}

假設我們今天多出一個儲存 Log 至資料庫的需求,想必很多朋友們會直覺的先想到再加一個 DatabaseLog 的方法。

修改後

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Logger
{
public void ConsoleLog(string message)
{
// 實作顯示 Log 至 Console
}

public void FileLog(string message)
{
// 實作儲存 Log 至檔案
}

public void DatabaseLog(string message)
{
// 實作儲存 Log 至資料庫
}
}

但是這樣真的好嗎,從 OCP 原則的角度來看,我們應該盡量減少 修改 這件事情,換句話說,不應該直接的修改 Log 的類別,應該要透過 擴充 的方式來加上新的功能。

而透過 OCP 原則,我們可以將原本的程式修改如下

再次修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public abstract class BaseLogger
{
public abstract void Log(string message);
}

public class ConsoleLogger : BaseLogger
{
public override void Log(string message)
{
// 實作 Console 的 Log 機制
}
}

public class FileLogger : BaseLogger
{
public override void Log(string message)
{
// 實作 File 的 Log 機制
}
}

public class DatabaseLogger : BaseLogger
{
public override void Log(string message)
{
// 實作 Database 的 Log 機制
}
}

我們可以建立一個抽象的 BaseLogger 類別,裡面有一個抽象的 Log 方法,每一個 Logger 都可以實作自己的 Log 機制。透過這種方式,不會每次增加一種 Log 方式就需要去更動到原本的 Logger 類別,這樣的作法就會符合前面所描述的 OCP 原則的定義。

對修改封閉、對擴充開放