2011/05/28

[Design Patterns] 狀態模式(State)

參考:大話設計模式
型態:行為模式(Behavioral Pattern)。
定義:當一個物件的內在狀態改變時允許改變其行為,這物件看起來像是改變了其類別。
使用時機: 當一個物件的行為取決於它的狀態,而且必須在執行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式。
結構圖:來源
2011-5-26 上午 07-19-55 
先來一個例子:參考   
TrafficLight .cs
using System.Threading;
namespace ConsoleApplication1 {
    public class TrafficLight {
        private enum eState { Red, Green, Yellow };
        private eState _State = eState.Red;

        public void Change() {
            switch (_State) { 
                case eState.Red:
                    Console.WriteLine("紅燈");
                    Sleep(5000);
                    this._State = eState.Green;
                    break;
                case eState.Green:
                    Console.WriteLine("綠燈");
                    Sleep(5000);
                    this._State = eState.Yellow;
                    break;
                case eState.Yellow:
                    Console.WriteLine("黃燈");
                    Sleep(5000);
                    this._State = eState.Red;
                    break;
            }
        }

        private void Sleep(int second) {
            try {
                Thread.Sleep(second);
            }catch{
                throw;
            }
        }
    }
}


<>  
Program.cs

class Program {
        static void Main(string[] args) {
            TrafficLight oTrafficLight = new TrafficLight();
            oTrafficLight.Change();
            oTrafficLight.Change();
            oTrafficLight.Change();
            Console.ReadKey();
        }
    }


輸出結果
2011-5-26 上午 07-56-29 

我們觀察 TrafficLight .cs 類別裡個 Change 方法,若是增加多個燈號或是其他如方向的狀態變化時, 這樣的寫法將會增加更多層次的判斷。
可以考慮讓每個狀態各自成為一個物件,負責自己該狀態的服務,並提供切換裝態的方法
<>  
TrafficLight .cs

 /// <summary>
    /// 狀態介面。
    /// </summary>
    public interface IState {
        void Change(TrafficLight light);
    }

    /// <summary>
    /// Light 抽象類別。
    /// </summary>
    public abstract class Light : IState {
        public abstract void Change(TrafficLight light);
        protected void Sleep(int second) {
            try { Thread.Sleep(second); }
            catch {throw;}
        }
    }

    /// <summary>
    /// 黃燈類別。
    /// </summary>
    public class Yellow : Light {
        public override void Change(TrafficLight light) {
            Console.WriteLine("黃燈");
            Sleep(5000);
            light.set(new Red()); // 如果考慮彈性調整狀態,可以不用寫死狀態物件設定
        }
    }

    /// <summary>
    /// 紅燈類別。
    /// </summary>
    public class Green : Light {
        public override void Change(TrafficLight light) {
            Console.WriteLine("綠燈");
            Sleep(5000);
            light.set(new Yellow()); // 如果考慮彈性調整狀態,可以不用寫死狀態物件設定
        }
    }

    /// <summary>
    /// 紅燈類別。
    /// </summary>
    public class Red : Light {
        public override void Change(TrafficLight light) {
            Console.WriteLine("紅燈");
            Sleep(5000);
            light.set(new Green()); // 如果考慮彈性調整狀態,可以不用寫死狀態物件設定
        }
    }

    /// <summary>
    /// 交通號誌類別。
    /// </summary>
    public class TrafficLight {         
        private IState current = new Red();
        public void set(IState state) { this.current = state; }    
        public void change() { current.Change(this); }       
    }


<>  <>
   
Program.cs

TrafficLight trafficLight = new TrafficLight(); 
while (true) { trafficLight.change(); }



輸出結果是一樣的
最後說明一下狀態模式的好處:
透過把各種狀態轉移邏輯分佈到 State 的子類別之間,來減少相互間的依賴。

0 Comments:

張貼留言