本文

1、內聚(Cohesion)

  • 把功能所需要的資料與程式都塞在某一個模組(fuction、class、package)中,使得該模組成為一個單獨的可執行個體。

大意上就是把程式跟所需要的資料全部都包在一起。
舉例:(不要懷疑我們最熟悉的特斯拉又來了)
今天我想要讓特斯拉具備螢幕、音響這些娛樂設施可以看電影,有了電影當然需要食物啊,那就需要有在特斯拉上吃爆米花的功能。

	//產生一個特斯拉類別有螢幕、音響、吃爆米花
        public class 特斯拉
        {
            public string 螢幕()
            {
                return "播放電影";
            }

            public string 音響()
            {
                return "杜比環繞音效";
            }

            public string 吃爆米花()
            {
                return "爆米花好吃";
            }
        }
		
	private static void Main(string[] args)
        {
            特斯拉 Tesla = new 特斯拉();
            Console.WriteLine("特斯拉 :" + Tesla.螢幕());
            Console.WriteLine("特斯拉開啟 :" + Tesla.音響());
            Console.WriteLine(Tesla.吃爆米花());
        }

這時候要提到程式設計常聽到的。

高內聚

  • 高內聚力的好處就是提高了模組的『獨立性』,也就是說這個模組可以被單獨使用,也可以被單獨修改。

那應該怎麼做呢?

  • 思考模組的關聯性。

以我們剛剛舉的例子特斯拉具備螢幕、音響這些娛樂設備是合理的,但吃爆米花的動作是不是在這個 Class 中顯得有點怪異了呢?

  • 特斯拉本身並不需要知道怎麼吃爆米花,需要知道怎麼吃爆米花的是人。

我們修改一下範例

	//產生一個特斯拉類別有螢幕、音響
        public class 特斯拉
        {
            public string 螢幕()
            {
                return "播放電影";
            }

            public string 音響()
            {
                return "杜比環繞音效";
            }
        }

        //產生一個人類別有吃爆米花的動作
        public class 
        {
            public string 吃爆米花()
            {
                return "爆米花好吃";
            }
        }
		
	private static void Main(string[] args)
        {
            特斯拉 Tesla = new 特斯拉();
            Console.WriteLine("特斯拉 :" + Tesla.螢幕());
            Console.WriteLine("特斯拉開啟 :" + Tesla.音響());

             Human = new ();
            Console.WriteLine("人在特斯拉上吃爆米花覺得:" + Human.吃爆米花());
        }

獨立出了特斯拉與人兩個 Class,特斯拉以後可以再加裝 KTV 設備,而人也可以增加唱歌這個動作,兩個模組具備自己的主題且獨立運作,亦可以獨立被使用。

2、耦合(Coupling)

  • Coupling(耦合):如果某個模組跟『其他人(另一個模組)』有關係(例如,使用 global variables 或是接受其他模組傳入的參數)那麼這兩個模組就彼此耦合。

簡單來說就是程式之間的關聯性。
2020/07/20 修改範例,跟同事聊完後,發現舉例不夠藕(?

舉例:今天特斯拉必須要有駕駛才能上路。

	 //產生一個特斯拉類別有上路的功能
        public class 特斯拉
        {
            public string 上路(駕駛 driver)
            {
                return driver.司機();
            }
        }

        //產生一個駕駛類別有一位司機
        public class 駕駛
        {
            public string 司機()
            {
                return "一位司機";
            }
        }
		
	 private static void Main(string[] args)
        {
            駕駛 driver = new 駕駛();
            特斯拉 Tesla = new 特斯拉();
            Console.WriteLine($"特斯拉上路有{Tesla.上路(driver)}");
        }

上述例子特斯拉就跟駕駛這個類別產生高度藕和的關係,當我想要將駕駛這個類別加入新東西時,特斯拉就會受到影響。
這時候又可以提到另一個觀念。

低耦合

要怎麼降低這個範例程式的耦合度呢?
我們可以將駕駛這個類別改成介面。

	//產生一個駕駛介面
        public interface Idriver
        {
            public string 駕駛();
        }

        //產生一個特斯拉類別有上路的功能並繼承駕駛介面
        public class 特斯拉 : Idriver
        {
            public string 上路()
            {
                return this.駕駛();
            }

            //實作駕駛這個類別
            public string 駕駛()
            {
                return "人類司機";
            }
        }
		
	private static void Main(string[] args)
        {
            特斯拉 Tesla = new 特斯拉();
            Console.WriteLine($"特斯拉上路有{Tesla.上路()}");
        }

如此一來特斯拉不直接依賴於駕駛,改成依賴於介面就降低了耦合度,今天特斯拉技術成長快速,真的能實際自動駕駛上路時我們也可以將駕駛抽換成自動駕駛如下…

	//產生一個駕駛介面
        public interface Idriver
        {
            public string 駕駛();
        }
		
	//產生一個特斯拉類別有上路的功能並繼承駕駛介面
        public class 特斯拉 : Idriver
        {
            public string 上路()
            {
                return this.駕駛();
            }

            //實作駕駛這個類別
            public string 駕駛()
            {
                return "自動駕駛";
            }
        }
		
	private static void Main(string[] args)
        {
            特斯拉 Tesla = new 特斯拉();
            Console.WriteLine($"特斯拉上路有{Tesla.上路()}");
        }

高內聚、低耦合最終目的

  • 需求異動容易抽換、修改與增加功能,而不會對太多既存功能造成影響。
  • 每個功能重用性高、擴展性好、維護性高。

參考資料