Design Pattern - State(C#)

版权声明:欢迎转载并请注明出处,谢谢~~ https://blog.csdn.net/chimomo/article/details/6051988

Definition

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Participants

    The classes and/or objects participating in this pattern are:

  • Context (Account)
    • Defines the interface of interest to clients
    • Maintains an instance of a ConcreteState subclass that defines the current state.
  • State (State)
    • Defines an interface for encapsulating the behavior associated with a particular state of the Context.
  • Concrete State (RedState, SilverState, GoldState)
    • Each subclass implements a behavior associated with a state of Context

Sample Code in C#

This structural code demonstrates the State pattern which allows an object to behave differently depending on its internal state. The difference in behavior is delegated to objects that represent this state.

/*
 * Structural State Design Pattern.
 */

namespace State.Sample
{
    using System;

    /// <summary>
    /// Startup class for Structural State Design Pattern.
    /// </summary>
    internal static class Program
    {
        #region Methods

        /// <summary>
        /// Entry point into console application.
        /// </summary>
        private static void Main()
        {
            // Setup context in a state.
            var c = new Context(new ConcreteStateA());

            // Issue requests, which toggles state.
            c.Request();
            c.Request();
            c.Request();
            c.Request();
        }

        #endregion
    }

    /// <summary>
    /// The 'State' abstract class.
    /// </summary>
    internal abstract class State
    {
        #region Public Methods and Operators

        /// <summary>
        /// Handle.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        public abstract void Handle(Context context);

        #endregion
    }

    /// <summary>
    /// A 'ConcreteState' class.
    /// </summary>
    internal class ConcreteStateA : State
    {
        #region Public Methods and Operators

        /// <summary>
        /// Handle.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        public override void Handle(Context context)
        {
            context.State = new ConcreteStateB();
        }

        #endregion
    }

    /// <summary>
    /// A 'ConcreteState' class.
    /// </summary>
    internal class ConcreteStateB : State
    {
        #region Public Methods and Operators

        /// <summary>
        /// Handle.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        public override void Handle(Context context)
        {
            context.State = new ConcreteStateA();
        }

        #endregion
    }

    /// <summary>
    /// The 'Context' class.
    /// </summary>
    internal class Context
    {
        #region Fields

        /// <summary>
        /// The state.
        /// </summary>
        private State _state;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Context"/> class.
        /// </summary>
        /// <param name="state">
        /// The state.
        /// </param>
        public Context(State state)
        {
            State = state;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the state.
        /// </summary>
        public State State
        {
            get { return _state; }

            set
            {
                _state = value;
                Console.WriteLine("State: " + _state.GetType().Name);
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Request.
        /// </summary>
        public void Request()
        {
            _state.Handle(this);
        }

        #endregion
    }
}

// Output:
/*
State: ConcreteStateA
State: ConcreteStateB
State: ConcreteStateA
State: ConcreteStateB
State: ConcreteStateA

*/

This real-world code demonstrates the State pattern which allows an Account to behave differently depending on its balance. The difference in behavior is delegated to State objects called RedState, SilverState and GoldState. These states represent overdrawn accounts, starter accounts, and accounts in good standing.

/*
 * Real-World State Design Pattern.
 */

namespace State.RealWorld
{
    using System;

    /// <summary>
    /// Startup class for Real-World State Design Pattern.
    /// </summary>
    internal static class Program
    {
        #region Methods

        /// <summary>
        /// Entry point into console application.
        /// </summary>
        private static void Main()
        {
            // Open a new account.
            var 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);
        }

        #endregion
    }

    /// <summary>
    /// The 'State' abstract class.
    /// </summary>
    internal abstract class State
    {
        #region Fields

        /// <summary>
        /// The account.
        /// </summary>
        protected Account account;

        /// <summary>
        /// The balance.
        /// </summary>
        protected double balance;

        /// <summary>
        /// The interest.
        /// </summary>
        protected double interest;

        /// <summary>
        /// The lower limit.
        /// </summary>
        protected double lowerLimit;

        /// <summary>
        /// The upper limit.
        /// </summary>
        protected double upperLimit;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the account.
        /// </summary>
        public Account Account
        {
            get { return account; }

            set { account = value; }
        }

        /// <summary>
        /// Gets or sets the balance.
        /// </summary>
        public double Balance
        {
            get { return balance; }

            set { balance = value; }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deposit.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public abstract void Deposit(double amount);

        /// <summary>
        /// Pay interest.
        /// </summary>
        public abstract void PayInterest();

        /// <summary>
        /// Withdraw.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public abstract void Withdraw(double amount);

        #endregion
    }

    /// <summary>
    /// A 'ConcreteState' class.
    /// <remarks>
    /// Red indicates that account is overdrawn.
    /// </remarks>
    /// </summary>
    internal class RedState : State
    {
        #region Fields

        /// <summary>
        /// The service fee.
        /// </summary>
        private double _serviceFee;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="RedState"/> class.
        /// </summary>
        /// <param name="state">
        /// The state.
        /// </param>
        public RedState(State state)
        {
            balance = state.Balance;
            account = state.Account;
            Initialize();
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deposit.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Deposit(double amount)
        {
            balance += amount;
            CheckStateChange();
        }

        /// <summary>
        /// Pay interest.
        /// </summary>
        public override void PayInterest()
        {
            // No interest is paid
        }

        /// <summary>
        /// Withdraw.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Withdraw(double amount)
        {
            amount = amount - _serviceFee;
            Console.WriteLine("No funds available for withdrawal!");
        }

        #endregion

        #region Methods

        /// <summary>
        /// Initialize.
        /// </summary>
        private void Initialize()
        {
            // Should come from a data source.
            interest = 0.0;
            lowerLimit = -100.0;
            upperLimit = 0.0;
            _serviceFee = 15.00;
        }

        /// <summary>
        /// Check state change.
        /// </summary>
        private void CheckStateChange()
        {
            if (balance > upperLimit)
            {
                account.State = new SilverState(this);
            }
        }

        #endregion
    }

    /// <summary>
    /// A 'ConcreteState' class.
    /// <remarks>
    /// Silver indicates a non-interest bearing state.
    /// </remarks>
    /// </summary>
    internal class SilverState : State
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SilverState"/> class.
        /// </summary>
        /// <param name="state">
        /// The state.
        /// </param>
        public SilverState(State state)
            : this(state.Balance, state.Account)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SilverState"/> class.
        /// </summary>
        /// <param name="balance">
        /// The balance.
        /// </param>
        /// <param name="account">
        /// The account.
        /// </param>
        public SilverState(double balance, Account account)
        {
            this.balance = balance;
            this.account = account;
            Initialize();
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deposit.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Deposit(double amount)
        {
            balance += amount;
            CheckStateChange();
        }

        /// <summary>
        /// Pay interest.
        /// </summary>
        public override void PayInterest()
        {
            balance += interest * balance;
            CheckStateChange();
        }

        /// <summary>
        /// Withdraw.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Withdraw(double amount)
        {
            balance -= amount;
            CheckStateChange();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Initialize.
        /// </summary>
        private void Initialize()
        {
            // Should come from a data source.
            interest = 0.0;
            lowerLimit = 0.0;
            upperLimit = 1000.0;
        }

        /// <summary>
        /// Check state change.
        /// </summary>
        private void CheckStateChange()
        {
            if (balance < lowerLimit)
            {
                account.State = new RedState(this);
            }
            else if (balance > upperLimit)
            {
                account.State = new GoldState(this);
            }
        }

        #endregion
    }

    /// <summary>
    /// A 'ConcreteState' class.
    /// <remarks>
    /// Gold indicates an interest bearing state.
    /// </remarks>
    /// </summary>
    internal class GoldState : State
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="GoldState"/> class.
        /// </summary>
        /// <param name="state">
        /// The state.
        /// </param>
        public GoldState(State state)
            : this(state.Balance, state.Account)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GoldState"/> class.
        /// </summary>
        /// <param name="balance">
        /// The balance.
        /// </param>
        /// <param name="account">
        /// The account.
        /// </param>
        private GoldState(double balance, Account account)
        {
            this.balance = balance;
            this.account = account;
            Initialize();
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deposit.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Deposit(double amount)
        {
            balance += amount;
            CheckStateChange();
        }

        /// <summary>
        /// Pay interest.
        /// </summary>
        public override void PayInterest()
        {
            balance += interest * balance;
            CheckStateChange();
        }

        /// <summary>
        /// Withdraw.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public override void Withdraw(double amount)
        {
            balance -= amount;
            CheckStateChange();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Initialize.
        /// </summary>
        private void Initialize()
        {
            // Should come from a database.
            interest = 0.05;
            lowerLimit = 1000.0;
            upperLimit = 10000000.0;
        }

        /// <summary>
        /// Check state change.
        /// </summary>
        private void CheckStateChange()
        {
            if (balance < 0.0)
            {
                account.State = new RedState(this);
            }
            else if (balance < lowerLimit)
            {
                account.State = new SilverState(this);
            }
        }

        #endregion
    }

    /// <summary>
    /// The 'Context' class.
    /// </summary>
    internal class Account
    {
        #region Fields

        /// <summary>
        /// The owner.
        /// </summary>
        private string _owner;

        /// <summary>
        /// The state.
        /// </summary>
        private State _state;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Account"/> class.
        /// </summary>
        /// <param name="owner">
        /// The owner.
        /// </param>
        public Account(string owner)
        {
            // New accounts are 'Silver' by default.
            _owner = owner;
            _state = new SilverState(0.0, this);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the balance.
        /// </summary>
        private double Balance => _state.Balance;

        /// <summary>
        /// Gets or sets the state.
        /// </summary>
        public State State
        {
            private get { return _state; }

            set { _state = value; }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Deposit.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public void Deposit(double amount)
        {
            _state.Deposit(amount);
            Console.WriteLine("Deposited {0:C} --- ", amount);
            Console.WriteLine(" Balance = {0:C}", Balance);
            Console.WriteLine(" Status = {0}", State.GetType().Name);
            Console.WriteLine(string.Empty);
        }

        /// <summary>
        /// Pay interest.
        /// </summary>
        public void PayInterest()
        {
            _state.PayInterest();
            Console.WriteLine("Interest Paid --- ");
            Console.WriteLine(" Balance = {0:C}", Balance);
            Console.WriteLine(" Status = {0}\n", State.GetType().Name);
        }

        /// <summary>
        /// Withdraw.
        /// </summary>
        /// <param name="amount">
        /// The amount.
        /// </param>
        public void Withdraw(double amount)
        {
            _state.Withdraw(amount);
            Console.WriteLine("Withdrew {0:C} --- ", amount);
            Console.WriteLine(" Balance = {0:C}", Balance);
            Console.WriteLine(" Status = {0}\n", State.GetType().Name);
        }

        #endregion
    }
}

// Output:
/*
Deposited ¥500.00 ---
 Balance = ¥500.00
 Status = SilverState

Deposited ¥300.00 ---
 Balance = ¥800.00
 Status = SilverState

Deposited ¥550.00 ---
 Balance = ¥1,350.00
 Status = GoldState

Interest Paid ---
 Balance = ¥1,417.50
 Status = GoldState

Withdrew ¥2,000.00 ---
 Balance = ¥-582.50
 Status = RedState

No funds available for withdrawal!
Withdrew ¥1,100.00 ---
 Balance = ¥-582.50
 Status = RedState


*/

猜你喜欢

转载自blog.csdn.net/chimomo/article/details/6051988
今日推荐