C#设计模式(19)——状态者模式(State Pattern)

原文:C#设计模式(19)——状态者模式(State Pattern)

一、引言

  在上一篇文章介绍到可以使用状态者模式和观察者模式来解决中介者模式存在的问题,在本文中将首先通过一个银行账户的例子来解释状态者模式,通过这个例子使大家可以对状态者模式有一个清楚的认识,接着,再使用状态者模式来解决上一篇文章中提出的问题。

二、状态者模式的介绍

  每个对象都有其对应的状态,而每个状态又对应一些相应的行为,如果某个对象有多个状态时,那么就会对应很多的行为。那么对这些状态的判断和根据状态完成的行为,就会导致多重条件语句,并且如果添加一种新的状态时,需要更改之前现有的代码。这样的设计显然违背了开闭原则。状态模式正是用来解决这样的问题的。状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为。

2.1 状态者模式的定义

  上面对状态模式做了一个简单的介绍,这里给出状态模式的定义。

  状态模式——允许一个对象在其内部状态改变时自动改变其行为,对象看起来就像是改变了它的类。

2.2 状态者模式的结构

  既然状态者模式是对已有对象的状态进行抽象,则自然就有抽象状态者类和具体状态者类,而原来已有对象需要保存抽象状态者类的引用,通过调用抽象状态者的行为来改变已有对象的行为。经过上面的分析,状态者模式的结构图也就很容易理解了,具体结构图如下图示。

  

  从上图可知,状态者模式涉及以下三个角色:

  • Account类:维护一个State类的一个实例,该实例标识着当前对象的状态。
  • State类:抽象状态类,定义了一个具体状态类需要实现的行为约定。
  • SilveStater、GoldState和RedState类:具体状态类,实现抽象状态类的每个行为。

2.3 状态者模式的实现

  下面,就以银行账户的状态来实现下状态者模式。银行账户根据余额可分为RedState、SilverState和GoldState。这些状态分别代表透支账号,新开账户和标准账户。账号余额在【-100.0,0.0】范围表示处于RedState状态,账号余额在【0.0 , 1000.0】范围表示处于SilverState,账号在【1000.0, 100000.0】范围表示处于GoldState状态。下面以这样的一个场景实现下状态者模式,具体实现代码如下所示:

  1 namespace StatePatternSample
  2 {
  3     public class Account
  4     {
  5         public State State {get;set;}
  6         public string Owner { get; set; }
  7         public Account(string owner)
  8         {
  9             this.Owner = owner;
 10             this.State = new SilverState(0.0, this);
 11         }
 12 
 13         public double Balance { get {return State.Balance; }} // 余额
 14         // 存钱
 15         public void Deposit(double amount)
 16         {
 17             State.Deposit(amount);
 18             Console.WriteLine("存款金额为 {0:C}——", amount);
 19             Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
 20             Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
 21             Console.WriteLine();
 22         }
 23 
 24         // 取钱
 25         public void Withdraw(double amount)
 26         {
 27             State.Withdraw(amount);
 28              Console.WriteLine("取款金额为 {0:C}——",amount);
 29             Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
 30             Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
 31             Console.WriteLine();
 32         }
 33 
 34         // 获得利息
 35         public void PayInterest()
 36         {
 37             State.PayInterest();
 38             Console.WriteLine("Interest Paid --- ");
 39             Console.WriteLine("账户余额为 =:{0:C}", this.Balance);
 40             Console.WriteLine("账户状态为: {0}", this.State.GetType().Name);
 41             Console.WriteLine();
 42         }
 43     }
 44 
 45     // 抽象状态类
 46     public abstract class State
 47     {
 48         // Properties
 49         public Account Account { get; set; }
 50         public double Balance { get; set; } // 余额
 51         public double Interest { get; set; } // 利率
 52         public double LowerLimit { get; set; } // 下限
 53         public double UpperLimit { get; set; } // 上限
 54 
 55         public abstract void Deposit(double amount); // 存款
 56         public abstract void Withdraw(double amount); // 取钱
 57         public abstract void PayInterest(); // 获得的利息
 58     }
 59 
 60     // Red State意味着Account透支了
 61     public class RedState : State
 62     {
 63         public RedState(State state)
 64         {
 65             // Initialize
 66             this.Balance = state.Balance;
 67             this.Account = state.Account;
 68             Interest = 0.00;
 69             LowerLimit = -100.00;
 70             UpperLimit = 0.00;
 71         }
 72 
 73         // 存款
 74         public override void Deposit(double amount)
 75         {
 76             Balance += amount;
 77             StateChangeCheck();
 78         }
 79         // 取钱
 80         public override void Withdraw(double amount)
 81         {
 82             Console.WriteLine("没有钱可以取了!");
 83         }
 84 
 85         public override void PayInterest()
 86         {
 87             // 没有利息
 88         }
 89 
 90         private void StateChangeCheck()
 91         {
 92             if (Balance > UpperLimit)
 93             {
 94                 Account.State = new SilverState(this);
 95             }
 96         }
 97     }
 98 
 99     // Silver State意味着没有利息得
100     public class SilverState :State
101     {
102         public SilverState(State state)
103             : this(state.Balance, state.Account)
104         { 
105         }
106 
107         public SilverState(double balance, Account account)
108         {
109             this.Balance = balance;
110             this.Account = account;
111             Interest = 0.00;
112             LowerLimit = 0.00;
113             UpperLimit = 1000.00;
114         }
115 
116         public override void Deposit(double amount)
117         {
118             Balance += amount;
119             StateChangeCheck();
120         }
121         public override void Withdraw(double amount)
122         {
123             Balance -= amount;
124             StateChangeCheck();
125         }
126 
127         public override void PayInterest()
128         {
129             Balance += Interest * Balance;
130             StateChangeCheck();
131         }
132 
133         private void StateChangeCheck()
134         {
135             if (Balance < LowerLimit)
136             {
137                 Account.State = new RedState(this);
138             }
139             else if (Balance > UpperLimit)
140             {
141                 Account.State = new GoldState(this);
142             }
143         }     
144     }
145 
146     // Gold State意味着有利息状态
147     public class GoldState : State
148     {
149         public GoldState(State state)
150         {
151             this.Balance = state.Balance;
152             this.Account = state.Account;
153             Interest = 0.05;
154             LowerLimit = 1000.00;
155             UpperLimit = 1000000.00;
156         }
157         // 存钱
158         public override void Deposit(double amount)
159         {
160             Balance += amount;
161             StateChangeCheck();
162         }
163         // 取钱
164         public override void Withdraw(double amount)
165         {
166             Balance -= amount;
167             StateChangeCheck();
168         }
169         public override void PayInterest()
170         {
171             Balance += Interest * Balance;
172             StateChangeCheck();
173         }
174 
175         private void StateChangeCheck()
176         {
177             if (Balance < 0.0)
178             {
179                 Account.State = new RedState(this);
180             }
181             else if (Balance < LowerLimit)
182             {
183                 Account.State = new SilverState(this);
184             }
185         }
186     }
187 
188     class App
189     {
190         static void Main(string[] args)
191         {
192             // 开一个新的账户
193             Account account = new Account("Learning Hard");
194 
195             // 进行交易
196             // 存钱
197             account.Deposit(1000.0);
198             account.Deposit(200.0);
199             account.Deposit(600.0);
200 
201             // 付利息
202             account.PayInterest();
203 
204             // 取钱
205             account.Withdraw(2000.00);
206             account.Withdraw(500.00);
207             
208             // 等待用户输入
209             Console.ReadKey();
210         }
211     }
212 }

  上面代码的运行结果如下图所示:

  从上图可以发现,进行存取款交易,会影响到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     }
View Code

四、状态者模式的应用场景

   在以下情况下可以考虑使用状态者模式。

  • 当一个对象状态转换的条件表达式过于复杂时可以使用状态者模式。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化。
  • 当一个对象行为取决于它的状态,并且它需要在运行时刻根据状态改变它的行为时,就可以考虑使用状态者模式。

五、状态者模式的优缺点

   状态者模式的主要优点是:

  • 将状态判断逻辑每个状态类里面,可以简化判断的逻辑。
  • 当有新的状态出现时,可以通过添加新的状态类来进行扩展,扩展性好。

  状态者模式的主要缺点是:

  • 如果状态过多的话,会导致有非常多的状态类,加大了开销。

六、总结

  状态者模式是对对象状态的抽象,从而把对象中对状态复杂的判断逻辑已到各个状态类里面,从而简化逻辑判断。在下一篇文章将分享我对策略模式的理解。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/453516.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OLTP与OLAP

当今的数据处理大致可以分成两大类&#xff1a;联机事务处理OLTP&#xff08;on-line transaction processing&#xff09;、联机分析处理OLAP&#xff08;On-Line Analytical Processing&#xff09;。OLTP是传统的关系型数据库的主要应用&#xff0c;主要是基本的、日常的事务…

揭秘IT人才特点:中美印日四国程序员比较

揭秘IT人才特点&#xff1a;中美印日四国程序员比较 最近以裁判的身份参加了公司举办的编程大赛&#xff0c;发现高手云集&#xff0c;对公司内部的程序员能力也有了更深入的了解。我觉得编程能力对程序员而言&#xff0c;虽然很重要&#xff0c;但并不是全部。那么作为一个程…

BaseColumns类的作用

这个类只是提供了两个字段&#xff0c;一个是"_id"一个是"_count"&#xff0c;便于调用数据库时导致拼写错误&#xff0c;你也可以扩展它&#xff0c;或者自定义这么个&#xff0c;然后直接调用它的常量名&#xff0c;防止写sql语句时把列名拼错 /** Copyr…

java如何限制输入值_[限制input输入类型]常用限制input方法

常用限制input的方法1.取消按钮按下时的虚线框,在input里添加属性值 hideFocus 或者 HideFocustrueinput type"submit" value"提交" hidefocus"true"2.只读文本框内容,在input里添加属性值 readonlyinput type"text" readonly3.防止退…

如何规范 CSS 的命名和书写

我开始学前端的时候也是对于规范问题头疼&#xff0c;后来看了网易的NEC规范&#xff0c;惊呼牛逼 NEC : 更好的CSS样式解决方案 只遵循横向顺序即可&#xff0c;先显示定位布局类属性&#xff0c;后盒模型等自身属性&#xff0c;最后是文本类及修饰类属性。 →显示属性自身属性…

app性能测试指标

性能测试在软件的质量保证中起着重要的作用&#xff0c;它包括的测试内容丰富多样。中国软件评测中心将性能测试概括为三个方面&#xff1a;应用在客户端性能的测试、应用在网络上性能的测试和应用在服务器端性能的测试。通常情况下&#xff0c;三方面有效、合理的结合&#xf…

《学做程序经理》完整版

文/Joel Spolsky 译/罗小平 指派一名优秀的程序经理&#xff0c;是团队产出优秀软件的重要前提之一。你的团队里可能没有这样的人&#xff0c;其实绝大多数团队都没有。 Charles Simonyi&#xff0c;这位曾与MarthaStewart&#xff08;译者注&#xff1a;美国女富豪&#…

java工程mvn引用jar_maven 项目加载本地JAR

将jar安装到本地的maven仓库1.首先确定本地有maven环境。2.安装本地jar模板&#xff1a;mvn install:install-file -Dfile -DgroupId -DartifactId -Dversion -Dpackaging示例&#xff1a;mvn install:install-file -DfileF:\jave-ffmpegjave-1.0.2.jar -DgroupIdffmpegjave -D…

compress()方法

boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream) 把位图的压缩信息写入到一个指定的输出流中。如果返回true&#xff0c;可以通过传递一个相应的输出流到BitmapFactory.decodeStream()来重构该位图。注意&#xff1a;并非所有的格式都直接支…

token的三点注意项

token的安全是极度重要的 1&#xff1a;token的唯一性&#xff0c; 它代表着来自某应用系统用户的一次成功登录。我们可以利用java util包工具直接生成一个32位唯一字符串来实现。 String token UUID.randomUUID().toString(); 同时&#xff0c;我们定义一个javabean&#xff…

0.1 js复习

1.1 JavaScript的用途 JavaScript用来制作web页面交互效果&#xff0c;提升用户体验。 能够制作的页面效果&#xff1a;轮播图&#xff0c;无限瀑布流&#xff0c;tab切换&#xff0c;定位地图&#xff0c;表单验证等。 web前端三层来说&#xff1a; 结构层 HTML 从语义的角度&…

优秀的软件企业为何倒下?

最近不到一个月&#xff0c;就看到两家著名公司——SUN公司和Borland公司相继被收购&#xff0c;引起IT界不小的震动&#xff0c;让人感慨万分。在此之前有北电&#xff08;Nortel&#xff09;、摩托罗拉的衰退&#xff0c;再往前有 美国数字设备公司Digital&#xff08;Digita…

python 列表的推导器和内置函数

# 列表的推导式# li []# for i in range(1,11):# li.append(i)# print(li)## lis [i for i in range(1,11)] #列表的推导式# print(lis)#[变量&#xff08;加工后的变量&#xff09; for 变量 i in 可迭代的数据类型】 列表的推导式# li2 []# for i in ran…

Android service 中的stub类

stub是为了方便client&#xff0c;service交互而生成出来的代码。 AIDL(android 接口描述语言)是一个IDL语言&#xff0c;它可以生成一段代码&#xff0c;可以使在一个android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如:在一个Activity中)访…

kafka exporter v0.3.0 发布: Prometheus官方推荐,欢迎试用

2019独角兽企业重金招聘Python工程师标准>>> 时隔1个半月&#xff0c;kakfa exporter v0.3.0于今日正式发布&#xff0c;欢迎大家试用。 项目地址 Github: https://github.com/danielqsj/kafka_exporter Docker Hub: https://hub.docker.com/r/danielqsj/kafka-expo…

java手动切换成独立显卡_JAVA设计模式之调停者模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述调停者(Mediator)模式的&#xff1a;调停者模式是对象的行为模式。调停者模式包装了一系列对象相互作用的方式&#xff0c;使得这些对象不必相互明显引用。从而使它们可以较松散地耦合。当这些对象中的某些对象之间的相互作用发…

2018.2.8 php实现qq登陆接口

PHP实现QQ登录的原理和实现过程 2018-02-08 学习与分享 PHP自学中心 第三方登录&#xff0c;就是使用大家比较熟悉的比如QQ、微信、微博等第三方软件登录自己的网站&#xff0c;这可以免去注册账号、快速留住用户的目的&#xff0c;免去了相对复杂的注册流程。下边就给大家讲一…

关于积累的一点看法

这是vip那边发表的一篇帖子&#xff0c;今天整理&#xff0c;发现可能有一点代表性&#xff0c;就再发在这里&#xff0c;供各位同学参考。 坛子里有人讨论小公司要不要积累框架的问题&#xff0c;有感而发&#xff0c;写了点自己的看法&#xff0c;一家之言&#xff0c;欢迎拍…

去除vue项目中的#及其ie9兼容性

一、如何去除vue项目中访问地址的# vue2中在路由配置中添加mode&#xff08;vue-cli创建的项目在src/router/index.js&#xff09; 1 export default new Router({2 mode: history,3 routes: [4 {5 path: /,6 name: menu,7 component: menu,8 …

sendBroadcast与sendStickyBroadcast的区别

前提条件&#xff1a;此处我主要讨论两种广播在代码中动态注册时的一些细节问题。 正常情况下&#xff0c;广播通常都是执行一次注册代码&#xff0c;就会触发各接收器接收一次&#xff0c;无论是在onCreate里注册还是onResume里注册&#xff1a;若在onCreate里注册&#xff0…