本文

開放封閉原則 Open-Close Principle(OCP)

定義

軟體設計原則,應該對擴展開放,對修改封閉。

甚麼意思呢?

  • 1、對擴展開放 - 程式碼對於新增功能是透過新增程式碼進行。
  • 2、對修改封閉 - 新增功能時不應該是更改現有程式碼。

那為甚麼要使用 OCP?

  • 1、程式碼可維護性提高。
  • 2、程式碼可擴展性提高。
  • 3、程式碼可複用、靈活性高。
  • 4、程式碼可測試性提高。

2020/09/08更新
寫完這篇跟同事討論過後決定要更改,一直發懶就放到現在,被迫要在進入下階段前先把前面要改的改完。
現在回頭看覺得當初為啥寫這例子怪怪的,回想起來才發現,原來我是為了避免使用到 DI 的觀念啊,但後來看了其他人寫的文章,用 DI 好像比較容易敘述這個概念…
所以就頭都要洗了,就先挖個坑吧。

我們來看一段例子,傳統汽車對於軟體硬體整合,還不夠靈活的時候,需要更改東西就需要把整台汽車拆開某些部分增加功能、每一次更改都是一項大工程。

	 public class 影音撥放器
        {
            public string 安裝()
            {
                return "安裝影音撥放器成功";
            }
        }

        public class 自動導航裝置
        {
            public string 安裝()
            {
                return "安裝自動導航裝置成功";
            }
        }

        public class 汽車
        {
            public string 安裝影音撥放器()
            {
                var 影音波放器 = new 影音撥放器();
                return 影音波放器.安裝();
            }

            public string 安裝自動導航裝置()
            {
                var 自動導航裝置 = new 自動導航裝置();
                return 自動導航裝置.安裝();
            }
        }
        
	 private static void Main(string[] args)
        {
            var 汽車 = new 汽車();
            Console.WriteLine($"汽車:{汽車.安裝影音撥放器()}");
            Console.WriteLine($"汽車:{汽車.安裝自動導航裝置()}");
        }

這時候發現如果我們要在加個停車導引功能的時候,又需要再把車子拆開來安裝停車導引系統;這時候我們可以看看特斯拉的作法,一開始先把車子硬體都準備好,當你有需要增加功能時對特斯拉來說就只是更新軟體而已。

	//更新軟體介面
	public interface I更新軟體
        {
            public string 安裝(string 安裝項目) 
            { 
                return ""; 
            }
        }

	//實作功能
        public class 更新軟體 : I更新軟體
        {
            public string 安裝(string 安裝項目)
            {
                return($"安裝{安裝項目}成功");
            }
        }

        public class 特斯拉
        {
            private readonly 更新軟體 _更新軟體;

            public 特斯拉(更新軟體 更新軟體)
            {
                this._更新軟體 = 更新軟體;
            }

            public string 安裝影音撥放器()
            {
                return this._更新軟體.安裝("影音撥放器");
            }

            public string 安裝自動導航裝置()
            {
                return this._更新軟體.安裝("自動導航裝置");
            }
			
	     public string 安裝停車導引系統()
            {
                return this._更新軟體.安裝("停車導引系統");
            }
        }
		
	private static void Main(string[] args)
        {
            //今天Models想增加功能時,就可以透過更新軟體安裝想要的功能。
            var ModelS = new 特斯拉(new 更新軟體());
            Console.WriteLine(ModelS.安裝影音撥放器());
            Console.WriteLine(ModelS.安裝自動導航裝置());
	     Console.WriteLine(ModelS.安裝停車導引系統());
        }

這樣就可以透過更新軟體來增加自己想要的功能,未來想要增加新功能時,也不需要更改其他地方只要針對特斯拉這個類別做更新就可以,以此達到OCP精神。
這邊的更新軟體作法是使用了 DI,後續文章會在說明DI用法,想先了解的可以先點此Dependency Injection概念介紹

參考連結