zoukankan      html  css  js  c++  java
  • 设计模式之状态模式

    状态模式类图:

     

    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的问题了。

  • 相关阅读:
    QWT编译与配置-Windows/Linux环境
    Manjaro Linux KDE个人的一些安装配置
    2019嵌入式之路的反思
    Linux内核调用I2C驱动_驱动嵌套驱动方法
    Ubuntu Linux TinySerial串口调试助手 可视化界面 安装使用
    ZYNQ的Linux Linaro系统镜像制作SD卡启动
    eclipse CDT Error: Program "g++" not found in PATH
    js Date格式化时间兼容写法
    ajax多图片上传demo
    php文件上传$_FILES数组格式
  • 原文地址:https://www.cnblogs.com/hankuikui/p/6995399.html
Copyright © 2011-2022 走看看