一、引言
上篇博客中学习了中介者模式,我们留下了一个问题,当出现多个玩家需要输赢状态条件判断时,可不可以不去修改中介者类,因为如果每新增一个条件判断,就要修改中介者类,破坏了封装,违背开闭原则。今天我们学习的内容就是要解决这种业务场景,状态模式
二、状态模式
定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
下面是状态模式的结构图:
下面是代码demo:

//维护一个ConcreteState子类的实例,这个实例定义当前状态 class Context { private State state; //定义Context的初始状态 public Context(State state) { this.State = state; } //可读写的State public State State { get { return state; } set { state = value; Console.WriteLine($"当前状态为{this.State.GetType().Name}"); } } //对请求做处理,并设置下一个状态 public void Request() { state.Handle(this); } } //抽象状态类 定义一个接口以封装与Context的一个特定状态相关的行为 abstract class State { public abstract void Handle(Context context); } class ConcreteStateA : State { //设置ConcreteStateA的下一个状态是ConcreteStateB public override void Handle(Context context) { context.State= new ConcreteStateB(); } } class ConcreteStateB : State { public override void Handle(Context context) { context.State = new ConcreteStateA(); } } class Program { static void Main(string[] args) { Context context = new Context(new ConcreteStateA()); context.Request(); context.Request(); context.Request(); Console.Read(); } }
分析:上面Context类中State不同时对应不同类ConcreteState中的行为,即将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
1.确保了新增状态及对应的行为时,不是去修改很长一大串if...else..逻辑判断。消除庞大的分支语句
2.把各种状态转移逻辑分布到State类的子类中,更加利于扩展
下面是大话设计模式中的例子:
场景:上午状态好,中午想睡觉,下午渐恢复,晚上苦煎熬

class Work { public State current; public Work() { current = new ForenoonState(); } public int hour; public int Hour { get { return hour; } set { hour = value; } } public bool finish; public bool TaskIsFinish { get { return finish; } set { finish = value; } } //设置当前状态 public void SetState(State state) { current = state; } public void WriteProgram() { current.WriteProgram(this); } } abstract class State { public abstract void WriteProgram(Work work); } class ForenoonState : State { public override void WriteProgram(Work work) { if(work.Hour<12) { Console.WriteLine("当前时间为{0}点,上午工作,精神充沛",work.Hour); } else { work.SetState(new NoonState()); work.WriteProgram(); } } } class NoonState : State { public override void WriteProgram(Work work) { if (work.Hour < 13) { Console.WriteLine("当前时间为{0}点,肚子饿了,午休,犯困",work.Hour); } else { work.SetState(new AfternoonState()); work.WriteProgram(); } } } class AfternoonState: State { public override void WriteProgram(Work work) { if (work.Hour < 17) { Console.WriteLine("当前时间为{0}点,下午状态还不错,继续努力", work.Hour); } else { work.SetState(new EveningState()); work.WriteProgram(); } } } class EveningState: State { public override void WriteProgram(Work work) { if (work.TaskIsFinish) { work.SetState(new ResetState()); work.WriteProgram(); } else { if(work.Hour<21) { Console.WriteLine("当前时间为{0}点,要加班哦,疲累至极", work.Hour); } else { work.SetState(new SleepingState()); work.WriteProgram(); } } } } class SleepingState: State { public override void WriteProgram(Work work) { Console.WriteLine("当前时间为{0}点,不行了,睡着了", work.Hour); } } class ResetState: State { public override void WriteProgram(Work work) { Console.WriteLine("当前时间为{0}点,下班了,回家了", work.Hour); } } class Program { static void Main(string[] args) { Work work = new Work(); work.Hour = 9; work.WriteProgram(); work.Hour = 12; work.WriteProgram(); work.Hour = 13; work.WriteProgram(); work.Hour = 17; // work.TaskIsFinish = true; work.WriteProgram(); work.Hour = 19; work.WriteProgram(); work.Hour = 23; work.WriteProgram(); Console.Read(); } }
分析:如果老板哪天要求“20点以后强制下班”,只需要新增加一个强制下班状态,稍微修改下傍晚状态类就可以了,而不会影响到其它状态类
下面是上篇博客中留下的问题,结合状态模式和中介者模式处理,下面是代码demo:

abstract class Mediator { public IList<Colleague> lstcolleague = new List<Colleague>(); public State State { get; set; } public Mediator(State state) { this.State = state; } public void Add(Colleague colleague) { lstcolleague.Add(colleague); } public void Remove(Colleague colleague) { lstcolleague.Remove(colleague); } public void Win(int number) { State.Win(number); } } class ConcreteMediator : Mediator { public ConcreteMediator(State state) : base(state) { } } abstract class State { public Mediator mediator; public abstract void Win(int number); } class ConcreteStateAWin : State { public ConcreteStateAWin(Mediator mediator) { this.mediator = mediator; } public override void Win(int number) { foreach (Colleague colleague in mediator.lstcolleague) { ConcreteColleagueA concreteColleagueA= colleague as ConcreteColleagueA; if(concreteColleagueA!=null) { concreteColleagueA.Number += number; } else { colleague.Number -= number; } } } } class ConcreteStateBWin : State { public ConcreteStateBWin(Mediator mediator) { this.mediator = mediator; } public override void Win(int number) { foreach (Colleague colleague in mediator.lstcolleague) { ConcreteColleagueB concreteColleagueB = colleague as ConcreteColleagueB; if (concreteColleagueB != null) { concreteColleagueB.Number += number; } else { colleague.Number -= number; } } } } class InitState : State { public InitState() { Console.WriteLine("游戏才刚刚开始"); } public override void Win(int number) { } } abstract class Colleague { public int Number { get; set; } public abstract void Win(int number,Mediator mediator); } class ConcreteColleagueA : Colleague { public override void Win(int number, Mediator mediator) { mediator.Win(number); } } class ConcreteColleagueB : Colleague { public override void Win(int number, Mediator mediator) { mediator.Win(number); } } class Program { static void Main(string[] args) { ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA(); ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB(); //初始化 concreteColleagueA.Number = 100; concreteColleagueB.Number = 100; ConcreteMediator concreteMediator = new ConcreteMediator(new InitState()); //玩家A和B 进入游戏 concreteMediator.lstcolleague.Add(concreteColleagueA); concreteMediator.lstcolleague.Add(concreteColleagueB); //玩家A赢了 concreteMediator.State = new ConcreteStateAWin(concreteMediator); concreteMediator.Win(5); Console.WriteLine($"A的数量为{concreteColleagueA.Number}"); Console.WriteLine($"B的数量为{concreteColleagueB.Number}"); Console.Read(); } }
分析:ok,解决了上面博客中的提出的两个问题,具体问题见上篇博客
优点:
1.将状态判断逻辑分到每个状态里面,减少了相互依赖,简化逻辑
2.当有新的状态出现时,可以通过新增状态来进行扩展,扩展性好
缺点:
1.当状态较多时,ConcreteState类较多,增加系统开销
适用场景:
1.当一个对象的行为取决于它的状态,并且必须在运行时刻根据状态改变行为时,就可以考虑状态模式
2.一个操作中有庞大的分支结构,并且这些分支结构取决于它的状态
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。