本文

OOP 原則了解完後,我們知道程式設計應該朝向『高內聚、低耦合』的概念設計,那怎麼設計呢?

這時候了解設計原則 SOLID 就很重要了…

1、Single Responsibility Principle(SRP) 單一職責

  • 大話設計模式:就一個類別而言,應該只有一個引起它變化的原因。

什麼意思呢?概念上就是,一個類別就只專注於完成一件事。
為甚麼要只專注於做一件事呢?
我們來看看範例,當今天特斯拉的駕駛走投無路需要賺外快的時候,他需要上路招攬客人…

	//產生一個駕駛類別要有開車、招攬客人、計算車資的功能。
        public class 駕駛
        {
            public string 開車()
            {
                return "開車上路";
            }

            public string 招攬客人()
            {
                return "有沒有人需要搭車";
            }

            public int 計算車資(int 搭車人數)
            {
                var 今天電價 = 30;

                var 每位乘客搭乘價格 = this.關注電價(今天電價);

                return 搭車人數 * 每位乘客搭乘價格;
            }

            public int 關注電價(int 每度時價)
            {
                if (每度時價 > 50)
                {
                    return 20;
                }
                return 10;
            }
        }
		
	private static void Main(string[] args)
        {
            駕駛 特斯拉駕駛 = new 駕駛();
            Console.WriteLine($"特斯拉駕駛{特斯拉駕駛.開車()}");
            Console.WriteLine($"特斯拉駕駛大喊{特斯拉駕駛.招攬客人()}");
            Console.WriteLine($"有四位乘客,特斯拉駕駛計算車資一共:{特斯拉駕駛.計算車資(4)}");
        }

現在駕駛這個類別一共要完成四件事:開車、招攬客人、計算車資、關注電價。
當今天駕駛真的還不出錢了他決定賣掉特斯拉改開油車,那我們就需要去更改計算車資跟關注電價這兩個地方。

  • 如果一個類別承擔的職責過多,就等於把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類別完成其他職責的能力。
  • 這種偶合會導致脆弱的設計,當變化發生時,設計會遭受到意想步道的破壞。

仔細思考,駕駛要開車招攬客人需要做到這麼多事嗎?

  • 關鍵:如果你能夠想到多於一個的動機去改變一個類別,那麼這個類別就具有多於一個的職責。

上一篇『高內聚』有提到『思考模組的關聯性。』駕駛其實只需要專注於開車這一件事就可以了,其他事我們可以交由 UBER 這個類別來幫忙完成。

	 //產生一個駕駛類別要有開車的功能。
        public class 駕駛
        {
            public string 開車()
            {
                return "開車上路";
            }
        }

        //產生Uber類別有招攬客人、計算車資、關注耗能時價的功能。
        public class Uber
        {
            public string 招攬客人()
            {
                return "尋找要搭車的人";
            }

            public int 計算車資(int 搭車人數)
            {
                var 每位乘客價格 = this.耗能時價("電");
                return 每位乘客價格 * 搭車人數;
            }

            public int 耗能時價(string 耗能)
            {
                var 今天電價 = 50;

                return 今天電價 > 50 ? 20 : 10;
            }
			
	private static void Main(string[] args)
        {
            駕駛 特斯拉駕駛 = new 駕駛();
            Console.WriteLine($"特斯拉駕駛{特斯拉駕駛.開車()}");

            Uber uber = new Uber();
            Console.WriteLine($"Uber{uber.招攬客人()}");
            Console.WriteLine($"有四位乘客,特斯拉駕駛計算車資一共{uber.計算車資(4)}");
        }

而當今天駕駛駕駛真的還不出錢了他決定賣掉特斯拉改開油車,那我們只需要修改Uber這個類別,計算耗能這個方法並把計算車資的地方改成用油如下…

	//產生一個駕駛類別要有開車的功能。
        public class 駕駛
        {
            public string 開車()
            {
                return "開車上路";
            }
        }

        //產生Uber類別有招攬客人、計算車資、關注耗能時價的功能。
        public class Uber
        {
            public string 招攬客人()
            {
                return "尋找要搭車的人";
            }

            public int 計算車資(int 搭車人數)
            {
                var 每位乘客價格 = this.耗能時價("油");
                return 每位乘客價格 * 搭車人數;
            }

            public int 耗能時價(string 耗能)
            {
                var 今天油價 = 30;
                var 今天電價 = 50;
                if (耗能 == "電")
                {
                    return 今天電價 > 50 ? 20 : 10;
                }
                return 今天油價 > 50 ? 15 : 10;
            }
        }
		
	private static void Main(string[] args)
        {
            駕駛 福特駕駛 = new 駕駛();
            Console.WriteLine($"福特駕駛{福特駕駛.開車()}");

            Uber uber = new Uber();
            Console.WriteLine($"Uber{uber.招攬客人()}");
            Console.WriteLine($"有四位乘客,福特駕駛計算車資一共{uber.計算車資(4)}");
        }

單一職責的優點:

  • 類別複雜性能夠降低,因為實現職責都有很清楚的定義。
  • 可讀性能夠提高。
  • 維護性也能提高。
  • 如果需要變更類別內容,引起的漣漪效應風險降低,擴展性很高。

單一職責,就是實作『高內聚』的方式。

參考連結