设计模式之状态模式

状态模式类图:

 

Context的request方法,根据自身的状态属性State, 执行state.handle方法,根据面向对象的多态原则,在运行时,由于可以动态修改Context的状态state,从而ConcreteState转化成另一个ConctreteState,执行各自的业务逻辑。

我总结状态模式要注意以下几点:

1. 在状态模式中,Context是持有状态的对象State,并可以修改状态setState.

2. 但是Context并不处理跟状态相关的行为,而是把处理状态的功能委托给了ConctreteState类来处理。

3. 在ConctreteState类中除了处理它的业务外,还要根据业务来修改Context的State,以达到修改状态的目的。(如果在Context中修改state就会有大量的if else)

4. 客户端一般只和Context交互。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象。

 来看一下代码:

假设银行账户的密码输入错误三次,账户状态改为Forbidden,如果输入错误6点,则locked.

public class Account
    {
        private readonly string password = "123456";

        private int tryCount = 0;

        public Account()
        {
            // 账启初始化时为,normal状态

            this.State = new Normal(this);
        }

        public AccountState State { get; set; }

        public void Validate(string pwd)
        {
            if (pwd != password)
            {
                tryCount++;

                State.Show(tryCount);
            }
        }

    }

    public abstract class AccountState
    {
        protected Account account;
        protected int maxTryCount;

        public abstract void Show(int tryCount);
    }

    public class Normal : AccountState
    {
        public Normal(Account account)
        {
            this.account = account;
            maxTryCount = 2;
        }

        public override void Show(int tryCount)
        {
            Console.WriteLine("Account State is Normal");
            StateChange(tryCount);
        }

        private void StateChange(int tryCount)
        {
            if (tryCount >= maxTryCount)
            {
                account.State = new Forbidden(this.account);
            }
        }

    }

    public class Forbidden : AccountState
    {
        public Forbidden(Account account) 
        {
            this.account = account;
            maxTryCount = 5;
        }

        public override void Show(int tryCount)
        {
            Console.WriteLine("Account State is Forbidden");
            StateChange(tryCount);

        }

        private void StateChange(int tryCount)
        {
            if (tryCount >= maxTryCount)
            {
                account.State = new Locked(account);
            }
        }

    }

    public class Locked : AccountState
    {
        public Locked(Account account)
        {
        }

        public override void Show(int tryCount)
        {
            Console.WriteLine("Account State is Locked");
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            Account account = new Account();

            for (int i = 0; i < 6; i++)
            {
                account.Validate("111111");
            }

            Console.ReadKey();
        }
    }

个人的总结:

1. 单纯的依靠状态模式没有很好的if else的问题,而且会产生大量的子类。

2. 子类之间的相互耦合,有点不能让人接受,哪果业务有变化:输入错误10次,就报警,那不仅要加一个类,而且还要修改locked类,没有做到开闭原则。

   当然可以把状态的修改放在context里,通过 if else方式来处理,这样就可以做到开闭原则,但是又回到1的问题了。

原文地址:https://www.cnblogs.com/hankuikui/p/6995399.html