2013年10月21日 星期一

OOAD原則 (二) Single Responsibility Principle 單一責任原則

SingleResponsibilityPrinciple主張 一個類別只有一個被修改的理由  一個類別只有一個職責
當一個類別可以做很多事情時  我們會稱他為God class  
通常這種類別的重覆使用性很低  因為他會跟很多其他的類別耦合  很難重覆使用

    class GodClass
    {
        private bool IsTurnOnTV = false;
        private bool IsTurnOnRadio = false;
        private bool IsTurnOnLight = false;
        public void TurnOnTV()
        {
            IsTurnOnTV = true;
            Console.WriteLine("TurnOnTV");
        }
        public void TurnOffTV()
        {
            IsTurnOnTV = false;
            Console.WriteLine("TurnOffTV");
        }
        public void TurnOnRadio()
        {
            IsTurnOnRadio = true;
            Console.WriteLine("TurnOnRadio");
        }
        public void TurnOffRadio()
        {
            IsTurnOnRadio = false;
            Console.WriteLine("TurnOffRadio");
        }

        public void TurnOnLight()
        {
            IsTurnOnLight = true; ;
            Console.WriteLine("TurnOnLight");
        }
        public void TurnOffLight()
        {
            IsTurnOnLight = false;
            Console.WriteLine("TurnOffLight");
        }

        public void Execute(string command)
        {
            switch (command)
            {
                case "TV":
                    if (IsTurnOnTV)
                        TurnOffTV();
                    else
                        TurnOnTV();
                    break;
                case "Light":
                    if(IsTurnOnLight)
                        TurnOffLight();
                    else
                        TurnOnLight();
                    break;
                case "Radio":
                    if (IsTurnOnRadio)
                        TurnOffRadio();
                    else
                        TurnOnRadio();
                    break;
                default:
                    throw new Exception();
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            GodClass godclass = new GodClass();
            godclass.Execute("Light");
            godclass.Execute("Light");
            Console.ReadKey();
        }
    }

上面是一個 god 類別的例子  他可以做 TV的開關  Light的開關 以及  Radio的開關
簡單的說就是甚麼都可以做  這樣寫好像不錯  所有控制的項目都整理在一個類別裡
但是  當有新的功能要要加入時  就得對execute的程式做修改  這樣就違反了OpenClosePrinciple
然後當新的需求不斷進來  最後  這個類別就會變成一個龐大而且充滿flag的類別
這樣的程式是非常難以維護的
但是  我們可以用下面的方式來做修改


  abstract class Command
    {
        public abstract void Execute();
    }
    class LightCommand : Command
    {
        private bool IsTurnOnLight = false;
        public void TurnOnLight()
        {
            IsTurnOnLight = true; ;
            Console.WriteLine("TurnOnLight");
        }
        public void TurnOffLight()
        {
            IsTurnOnLight = false;
            Console.WriteLine("TurnOffLight");
        }
        public override void Execute()
        {
            if (IsTurnOnLight)
                TurnOffLight();
            else
                TurnOnLight();
        }
    }

    class TVCommand : Command
    {
        private bool IsTurnOnTV = false;
        public void TurnOnTV()
        {
            IsTurnOnTV = true;
            Console.WriteLine("TurnOnTV");
        }
        public void TurnOffTV()
        {
            IsTurnOnTV = false;
            Console.WriteLine("TurnOffTV");
        }
        public override void Execute()
        {
            if (IsTurnOnTV)
                TurnOffTV();
            else
                TurnOnTV();
        }
    }

    class RadioCommand : Command
    {
        private bool IsTurnOnRadio = false;
        public void TurnOnRadio()
        {
            IsTurnOnRadio = true;
            Console.WriteLine("TurnOnRadio");
        }
        public void TurnOffRadio()
        {
            IsTurnOnRadio = false;
            Console.WriteLine("TurnOffRadio");
        }
        public override void Execute()
        {
            if (IsTurnOnRadio)
                TurnOffRadio();
            else
                TurnOnRadio();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Command LightCommand = new LightCommand();
            LightCommand.Execute();
            LightCommand.Execute();
            Console.ReadKey();
        }
    }
基本上這兩段程式碼做的事情是一樣的
但是上面這一段程式碼
當新的需求進來時   例如我想新增電腦開關
不論我在新的類別裡面修改或新增了多少東西
並不會影響到其他已經寫好的類別
對維護者來說  這樣的類別也是相對好維護的  flag少而且執行的功能明確
這就是把責任切開的好處

沒有留言:

張貼留言