设计模式——状态模式
允许一个对象在改变它的内部状态时改变他的行为。对象看起来似乎改变了它的类
适用性
- 一个对象的行为取决于他的状态,并且他必须在运行时刻根据状态改变他的行为
- 一个操作中含有庞大的多分支的的条件语句,且这些分支依赖于对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的的条件结构。State模式将每一个条件分支放入一个单独的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖与其他对象而单独存在
参与者
Context
——定义客户感兴趣的接口
——维护一个ConcreteState子类的实例,这个实例定义当前状态
State
——定义一个接口以封装与Context的一个特定状态相关的行为
ConcreteState Subclasses
——每一个子类实现一个与Context的一个特定状态相关的行为
下面,就以银行账户的状态来实现下状态者模式。银行账户根据余额可分为RedState、SilverState和GoldState。这些状态分别代表透支账号,新开账户和标准账户。账号余额在【-100.0,0.0】范围表示处于RedState状态,账号余额在【0.0 , 1000.0】范围表示处于SilverState,账号在【1000.0, 100000.0】范围表示处于GoldState状态。下面以这样的一个场景实现下状态者模式,具体实现代码如下所示:
1 public class Account 2 { 3 public State State {get;set;} 4 public string Owner { get; set; } 5 public Account(string owner) 6 { 7 this.Owner = owner; 8 this.State = new SilverState(0.0, this); 9 } 10 11 public double Balance { get {return State.Balance; }} // 余额 12 // 存钱 13 public void Deposit(double amount) 14 { 15 State.Deposit(amount); 16 Console.WriteLine("存款金额为 {0:C}——", amount); 17 Console.WriteLine("账户余额为 =:{0:C}", this.Balance); 18 Console.WriteLine("账户状态为: {0}", this.State.GetType().Name); 19 Console.WriteLine(); 20 } 21 22 // 取钱 23 public void Withdraw(double amount) 24 { 25 State.Withdraw(amount); 26 Console.WriteLine("取款金额为 {0:C}——",amount); 27 Console.WriteLine("账户余额为 =:{0:C}", this.Balance); 28 Console.WriteLine("账户状态为: {0}", this.State.GetType().Name); 29 Console.WriteLine(); 30 } 31 32 // 获得利息 33 public void PayInterest() 34 { 35 State.PayInterest(); 36 Console.WriteLine("Interest Paid --- "); 37 Console.WriteLine("账户余额为 =:{0:C}", this.Balance); 38 Console.WriteLine("账户状态为: {0}", this.State.GetType().Name); 39 Console.WriteLine(); 40 } 41 }
1 // 抽象状态类 2 public abstract class State 3 { 4 // Properties 5 public Account Account { get; set; } 6 public double Balance { get; set; } // 余额 7 public double Interest { get; set; } // 利率 8 public double LowerLimit { get; set; } // 下限 9 public double UpperLimit { get; set; } // 上限 10 11 public abstract void Deposit(double amount); // 存款 12 public abstract void Withdraw(double amount); // 取钱 13 public abstract void PayInterest(); // 获得的利息 14 }
1 // Red State意味着Account透支了 2 public class RedState : State 3 { 4 public RedState(State state) 5 { 6 // Initialize 7 this.Balance = state.Balance; 8 this.Account = state.Account; 9 Interest = 0.00; 10 LowerLimit = -100.00; 11 UpperLimit = 0.00; 12 } 13 14 // 存款 15 public override void Deposit(double amount) 16 { 17 Balance += amount; 18 StateChangeCheck(); 19 } 20 // 取钱 21 public override void Withdraw(double amount) 22 { 23 Console.WriteLine("没有钱可以取了!"); 24 } 25 26 public override void PayInterest() 27 { 28 // 没有利息 29 } 30 31 private void StateChangeCheck() 32 { 33 if (Balance > UpperLimit) 34 { 35 Account.State = new SilverState(this); 36 } 37 } 38 }
1 // Silver State意味着没有利息得 2 public class SilverState :State 3 { 4 public SilverState(State state) 5 : this(state.Balance, state.Account) 6 { 7 } 8 9 public SilverState(double balance, Account account) 10 { 11 this.Balance = balance; 12 this.Account = account; 13 Interest = 0.00; 14 LowerLimit = 0.00; 15 UpperLimit = 1000.00; 16 } 17 18 public override void Deposit(double amount) 19 { 20 Balance += amount; 21 StateChangeCheck(); 22 } 23 public override void Withdraw(double amount) 24 { 25 Balance -= amount; 26 StateChangeCheck(); 27 } 28 29 public override void PayInterest() 30 { 31 Balance += Interest * Balance; 32 StateChangeCheck(); 33 } 34 35 private void StateChangeCheck() 36 { 37 if (Balance < LowerLimit) 38 { 39 Account.State = new RedState(this); 40 } 41 else if (Balance > UpperLimit) 42 { 43 Account.State = new GoldState(this); 44 } 45 } 46 }
1 // Gold State意味着有利息状态 2 public class GoldState : State 3 { 4 public GoldState(State state) 5 { 6 this.Balance = state.Balance; 7 this.Account = state.Account; 8 Interest = 0.05; 9 LowerLimit = 1000.00; 10 UpperLimit = 1000000.00; 11 } 12 // 存钱 13 public override void Deposit(double amount) 14 { 15 Balance += amount; 16 StateChangeCheck(); 17 } 18 // 取钱 19 public override void Withdraw(double amount) 20 { 21 Balance -= amount; 22 StateChangeCheck(); 23 } 24 public override void PayInterest() 25 { 26 Balance += Interest * Balance; 27 StateChangeCheck(); 28 } 29 30 private void StateChangeCheck() 31 { 32 if (Balance < 0.0) 33 { 34 Account.State = new RedState(this); 35 } 36 else if (Balance < LowerLimit) 37 { 38 Account.State = new SilverState(this); 39 } 40 } 41 }
1 class App 2 { 3 static void Main(string[] args) 4 { 5 // 开一个新的账户 6 Account account = new Account("Learning Hard"); 7 8 // 进行交易 9 // 存钱 10 account.Deposit(1000.0); 11 account.Deposit(200.0); 12 account.Deposit(600.0); 13 14 // 付利息 15 account.PayInterest(); 16 17 // 取钱 18 account.Withdraw(2000.00); 19 account.Withdraw(500.00); 20 21 // 等待用户输入 22 Console.ReadKey(); 23 } 24 } 25 }
从上图可以发现,进行存取款交易,会影响到Account内部的状态,由于状态的改变,从而影响到Account类行为的改变,而且这些操作都是发生在运行时的。
应用状态者模式完善中介者模式方案
1 // 抽象牌友类 2 public abstract class AbstractCardPartner 3 { 4 public int MoneyCount { get; set; } 5 6 public AbstractCardPartner() 7 { 8 MoneyCount = 0; 9 } 10 11 public abstract void ChangeCount(int Count, AbstractMediator mediator); 12 } 13 14 // 牌友A类 15 public class ParterA : AbstractCardPartner 16 { 17 // 依赖与抽象中介者对象 18 public override void ChangeCount(int Count, AbstractMediator mediator) 19 { 20 mediator.ChangeCount(Count); 21 } 22 } 23 24 // 牌友B类 25 public class ParterB : AbstractCardPartner 26 { 27 // 依赖与抽象中介者对象 28 public override void ChangeCount(int Count, AbstractMediator mediator) 29 { 30 mediator.ChangeCount(Count); 31 } 32 } 33 34 // 抽象状态类 35 public abstract class State 36 { 37 protected AbstractMediator meditor; 38 public abstract void ChangeCount(int count); 39 } 40 41 // A赢状态类 42 public class AWinState : State 43 { 44 public AWinState(AbstractMediator concretemediator) 45 { 46 this.meditor = concretemediator; 47 } 48 49 public override void ChangeCount(int count) 50 { 51 foreach (AbstractCardPartner p in meditor.list) 52 { 53 ParterA a = p as ParterA; 54 // 55 if (a != null) 56 { 57 a.MoneyCount += count; 58 } 59 else 60 { 61 p.MoneyCount -= count; 62 } 63 } 64 } 65 } 66 67 // B赢状态类 68 public class BWinState : State 69 { 70 public BWinState(AbstractMediator concretemediator) 71 { 72 this.meditor = concretemediator; 73 } 74 75 public override void ChangeCount(int count) 76 { 77 foreach (AbstractCardPartner p in meditor.list) 78 { 79 ParterB b = p as ParterB; 80 // 如果集合对象中时B对象,则对B的钱添加 81 if (b != null) 82 { 83 b.MoneyCount += count; 84 } 85 else 86 { 87 p.MoneyCount -= count; 88 } 89 } 90 } 91 } 92 93 // 初始化状态类 94 public class InitState : State 95 { 96 public InitState() 97 { 98 Console.WriteLine("游戏才刚刚开始,暂时还有玩家胜出"); 99 } 100 101 public override void ChangeCount(int count) 102 { 103 // 104 return; 105 } 106 } 107 108 // 抽象中介者类 109 public abstract class AbstractMediator 110 { 111 public List<AbstractCardPartner> list = new List<AbstractCardPartner>(); 112 113 public State State { get; set; } 114 115 public AbstractMediator(State state) 116 { 117 this.State = state; 118 } 119 120 public void Enter(AbstractCardPartner partner) 121 { 122 list.Add(partner); 123 } 124 125 public void Exit(AbstractCardPartner partner) 126 { 127 list.Remove(partner); 128 } 129 130 public void ChangeCount(int count) 131 { 132 State.ChangeCount(count); 133 } 134 } 135 136 // 具体中介者类 137 public class MediatorPater : AbstractMediator 138 { 139 public MediatorPater(State initState) 140 : base(initState) 141 { } 142 } 143 144 class Program 145 { 146 static void Main(string[] args) 147 { 148 AbstractCardPartner A = new ParterA(); 149 AbstractCardPartner B = new ParterB(); 150 // 初始钱 151 A.MoneyCount = 20; 152 B.MoneyCount = 20; 153 154 AbstractMediator mediator = new MediatorPater(new InitState()); 155 156 // A,B玩家进入平台进行游戏 157 mediator.Enter(A); 158 mediator.Enter(B); 159 160 // A赢了 161 mediator.State = new AWinState(mediator); 162 mediator.ChangeCount(5); 163 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount);// 应该是25 164 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是15 165 166 // B 赢了 167 mediator.State = new BWinState(mediator); 168 mediator.ChangeCount(10); 169 Console.WriteLine("A 现在的钱是:{0}", A.MoneyCount);// 应该是25 170 Console.WriteLine("B 现在的钱是:{0}", B.MoneyCount); // 应该是15 171 Console.Read(); 172 } 173 }
状态者模式是对对象状态的抽象,从而把对象中对状态复杂的判断逻辑已到各个状态类里面,从而简化逻辑判断。在下一篇文章将分享我对策略模式的理解。