الگوی State

الگوی State(وضعیت) در دسته الگوهای رفتاری قرار دارد.اجازه دادن به یک شیء رفتار خود را تغییر دهد زمانی که وضعیت داخلی آن تغییر می کند.شیء به نظر می رسد که کلاس خود را تغییر داده است.به عبارت دیگر فراهم کردن قابلیت تغییر رفتار برای یک شی در حالت های مختلف وضعیت آن.UML class diagram شركت كنندگان کلاس ها و اشیاء شرکت کننده در این الگو عبارتند از:زمینه Context (حساب در مثال دنیای واقعی Account):واسط(Interface) مورد علاقه کلاینت را تعریف می کند.یک نمونه از زیر کلاس کلاس ConcreteState که وضعیت فعلی را تعریف می کند نگه می دارد.نکته: درخواست (Request())متدی از Context است که قارا است بسته به وضعیت Context رفتار متفاوتی داشته باشد.به عبارت دیگر کلاسی است که قرار است رفتارش بسته وضعیتش تغییر کند. این کلاس حاوی به یک شی از جنس state است که معادل وضعیت جاری است. وضعیت State (وضعیت State) :تعریف یک واسط برای کپسوله سازی رفتار مرتبط با یک وضعیت خاص از زمینه(Context).به عبارت دیگر کلاس مجردی است که ساختار همه ی وضعیت ها و همچنین رفتار مبتنی بر وضعیت را تعریف می کند.نکته: اداره کننده-مدیریت کننده (Handle()) متدی انتزاعی است که توسط State تعریف میشود تا کلاس Context با فراخوانی آن در متد Request() خود بتواند با تمام اشیا وضعیت کار کند و متد Request رفتار متفاوتی بروز بدهد.وضعیت سفت ConcreteState (وضعیت قرمز ، نقره ای ، طلاییRedState, SilverState, GoldState) :هر یک از زیر کلاسها یک رفتار مرتبط با حالت زمینه(Context) را پیاده سازی می کند. به عبارت دیگر پیاده سازی های مختلفی از State است که هر کدام آنها به معنی وضعیتی از Context بوده و رفتار Context.Request() در آن وضعیت را نگهداری می کند. ساختار کلی کدالگوی وضعیت را نشان می دهد که اجازه می دهد یک شی به طور متفاوت با توجه به وضعیت داخلی آن رفتار کند. تفاوت در رفتار، به اشیایی که این حالت را نشان می دهند منتقل می شود. using System; namespace DoFactory.GangOfFour.State.Structural { /// <summary> /// MainApp startup class for Structural /// State Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main () { // Setup context in a state Context c = new Context (new ConcreteStateA ()); // Issue requests, which toggles state c.Request (); c.Request (); c.Request (); c.Request (); // Wait for user Console.ReadKey (); } } /// <summary> /// The 'State' abstract class /// </summary> abstract class State { public abstract void Handle (Context context); } /// <summary> /// A 'ConcreteState' class /// </summary> class ConcreteStateA : State { public override void Handle (Context context) { context.State = new ConcreteStateB (); } } /// <summary> /// A 'ConcreteState' class /// </summary> class ConcreteStateB : State { public override void Handle (Context context) { context.State = new ConcreteStateA (); } } /// <summary> /// The 'Context' class /// </summary> class Context { private State _state; // Constructor public Context (State state) { this.State = state; } // Gets or sets the state public State State { get { return _state; } set { _state = value; Console.WriteLine ("State: " + _state.GetType ().Name); } } public void Request () { _state.Handle (this); } } } OutputState : ConcreteStateAState : ConcreteStateBState : ConcreteStateAState : ConcreteStateBState : ConcreteStateAمثال دنیای واقعی: الگوی وضعیت را نشان می دهد که اجازه می دهد یک حساب به تنهایی با توجه به موجودی( balance ) آن رفتار کند.تفاوت در رفتار به اشیاء وضعیت به نام RedState، SilverState و GoldState اعطا می شود.این وظایف حساب های بی اعتبار، حساب های شروع کننده و حساب های دارای وضعیت خوب را نشان می دهند. using System; namespace DoFactory.GangOfFour.State.RealWorld { /// <summary> /// MainApp startup class for Real-World /// State Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main () { // Open a new account Account account = new Account ("Jim Johnson"); // Apply financial transactions account.Deposit (500.0); account.Deposit (300.0); account.Deposit (550.0); account.PayInterest (); account.Withdraw (2000.00); account.Withdraw (1100.00); // Wait for user Console.ReadKey (); } } /// <summary> /// The 'State' abstract class /// </summary> abstract class State { protected Account account; protected double balance; protected double interest; protected double lowerLimit; protected double upperLimit; // Properties public Account Account { get { return account; } set { account = value; } } public double Balance { get { return balance; } set { balance = value; } } public abstract void Deposit (double amount); public abstract void Withdraw (double amount); public abstract void PayInterest (); } /// <summary> /// A 'ConcreteState' class /// <remarks> /// Red indicates that account is overdrawn /// </remarks> /// </summary> class RedState : State { private double _serviceFee; // Constructor public RedState (State state) { this.balance = state.Balance; this.account = state.Account; Initialize (); } private void Initialize () { // Should come from a datasource interest = 0.0; lowerLimit = -100.0; upperLimit = 0.0; _serviceFee = 15.00; } public override void Deposit (double amount) { balance += amount; StateChangeCheck (); } public override void Withdraw (double amount) { amount = amount - _serviceFee; Console.WriteLine ("No funds available for withdrawal!"); } public override void PayInterest () { // No interest is paid } private void StateChangeCheck () { if (balance > upperLimit) { account.State = new SilverState (this); } } } /// <summary> /// A 'ConcreteState' class /// <remarks> /// Silver indicates a non-interest bearing state /// </remarks> /// </summary> class SilverState : State { // Overloaded constructors public SilverState (State state): this (state.Balance, state.Account) { } public SilverState (double balance, Account account) { this.balance = balance; this.account = account; Initialize (); } private void Initialize () { // Should come from a datasource interest = 0.0; lowerLimit = 0.0; upperLimit = 1000.0; } public override void Deposit (double amount) { balance += amount; StateChangeCheck (); } public override void Withdraw (double amount) { balance -= amount; StateChangeCheck (); } public override void PayInterest () { balance += interest * balance; StateChangeCheck (); } private void StateChangeCheck () { if (balance < lowerLimit) { account.State = new RedState (this); } else if (balance > upperLimit) { account.State = new GoldState (this); } } } /// <summary> /// A 'ConcreteState' class /// <remarks> /// Gold indicates an interest bearing state /// </remarks> /// </summary> class GoldState : State { // Overloaded constructors public GoldState (State state) : this (state.Balance, state.Account) { } public GoldState (double balance, Account account) { this.balance = balance; this.account = account; Initialize (); } private void Initialize () { // Should come from a database interest = 0.05; lowerLimit = 1000.0; upperLimit = 10000000.0; } public override void Deposit (double amount) { balance += amount; StateChangeCheck (); } public override void Withdraw (double amount) { balance -= amount; StateChangeCheck (); } public override void PayInterest () { balance += interest * balance; StateChangeCheck (); } private void StateChangeCheck () { if (balance < 0.0) { account.State = new RedState (this); } else if (balance < lowerLimit) { account.State = new SilverState (this); } } } /// <summary> /// The 'Context' class /// </summary> class Account { private State _state; private string _owner; // Constructor public Account (string owner) { // New accounts are 'Silver' by default this._owner = owner; this._state = new SilverState (0.0, this); } // Properties public double Balance { get { return _state.Balance; } } public State State { get { return _state; } set { _state = value; } } public void Deposit (double amount) { _state.Deposit (amount); Console.WriteLine ("Deposited {0:C} --- ", amount); Console.WriteLine (" Balance = {0:C}", this.Balance); Console.WriteLine (" Status = {0}", this.State.GetType ().Name); Console.WriteLine (""); } public void Withdraw (double amount) { _state.Withdraw (amount); Console.WriteLine ("Withdrew {0:C} --- ", amount); Console.WriteLine (" Balance = {0:C}", this.Balance); Console.WriteLine (" Status = {0}\n", this.State.GetType ().Name); } public void PayInterest () { _state.PayInterest (); Console.WriteLine ("Interest Paid --- "); Console.WriteLine (" Balance = {0:C}", this.Balance); Console.WriteLine (" Status = {0}\n", this.State.GetType ().Name); } } } OutputDeposited $500.00 --- Balance = $500.00 Status = SilverStateDeposited $300.00 --- Balance = $800.00 Status = SilverStateDeposited $550.00 --- Balance = $1,350.00 Status = GoldStateInterest Paid --- Balance = $1,417.50 Status = GoldStateWithdrew $2,000.00 --- Balance = ($582.50) Status = RedStateNo funds available for withdrawal!Withdrew $1,100.00 --- Balance = ($582.50) Status = RedStateمنبع