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,一经查实,立即删除!

相关文章

如何规范 CSS 的命名和书写

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

《学做程序经理》完整版

文/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…

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

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

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;使得这些对象不必相互明显引用。从而使它们可以较松散地耦合。当这些对象中的某些对象之间的相互作用发…

Hadoop2.6.0完全分布式安装

1、修改主机名称 对master/slave1/slave2同时配置为Master/Slave1/Slave2 masterMaster:~$ sudo gedit /etc/hostname 上述3个虚机结点均需要进行以上步骤 2、填写主机IP 对master/slave1/slave2同时配置 masterMaster:~$ sudo gedit /etc/hosts 192.168.48.128 master192.168.…

DEX加密效果分析

dex加密目的&#xff1a;保护安卓应用的Java源代码&#xff0c;避免被恶意分析&#xff0c;技术被窃取准备工具&#xff1a;1、apktool &#xff1a;反编译apk&#xff0c;提取smali代码2、dex2jar &#xff1a;将dex转化为jar文件3、jd-gui &#xff1a;查看jar文件&#xff0…

kd树的原理

kd树就是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构&#xff0c;可以运用在k近邻法中&#xff0c;实现快速k近邻搜索。构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分。    假设数据集\(T\)的大小是\(m*n\),即\(T{x_1,x_2,...x_m}\),其中…

力软 java主从表保存_JAVA常用知识总结(十二)——数据库(二)

MySQL主从热备份工作原理简单的说&#xff1a;就是主服务器上执行过的sql语句会保存在binLog里面&#xff0c;别的从服务器把他同步过来&#xff0c;然后重复执行一遍&#xff0c;那么它们就能一直同步啦。整体上来说&#xff0c;复制有3个步骤&#xff1a;作为主服务器的Maste…

Java——线程的创建,线程池

线程 多线程就是一个程序中有多个线程在同时执行。 多线程下CPU的工作原理 实际上&#xff0c;CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言&#xff0c;某个时刻&#xff0c;只能执行一个线程&#xff0c;而CPU的在多个线程间切换速度…

java并查集找朋友圈_图—并查集(解决朋友圈问题)

图也是一种 非线性结构&#xff0c;是由多个顶点组成的关系集合组成的一种数据结构。图可以分为两种&#xff0c;无向图和有向图。★图的定义:★典型问题&#xff1a;利用图能够解决很多问题&#xff0c;这里有一个较为典型的问题&#xff0c;假如已知有n个人和m对好友关系(存于…

(三)SpringBoot之配置文件详解:Properties和YAML

一、配置文件的生效顺序&#xff0c;会对值进行覆盖&#xff1a; 1. TestPropertySource 注解2. 命令行参数3. Java系统属性&#xff08;System.getProperties()&#xff09;4. 操作系统环境变量5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource6. 在打包的j…

fscanf()php,fscanf函数的用法

以前解析有规律的文件的时候要么用正则表达式&#xff0c;要么就是傻傻的自己写程序来解析有规律的文件。今天突然发现c的库函数中有一个现成的可以解析有规律的文件的函数&#xff0c;就是fscanf()函数。fscanf 位于头文件中&#xff0c;函数原型为 int fscanf(FILE * stream,…

为什么设计师应该学习编写代码

通常&#xff0c;在完成了一件网页设计后&#xff0c;设计师的无知都会显露无遗而备受指责。他们把创建网页代码的繁重工作都留给了程序员们。这种现象不只出现在网络开发行业&#xff0c;在软件及游戏开发业也是如此&#xff08;完整图文版&#xff09;。残酷的事实就是&#…

iOS内存区域部分内容

目前参考这里&#xff1a; https://www.zhihu.com/question/263823072/answer/273452932 以后整理相关的代码问题。 更多参考资料&#xff1a; https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap 堆栈&#xff1a;https://baike.baidu.com/ite…

浅析Numpy.genfromtxt及File I/O讲解

Python 并没有提供数组功能&#xff0c;虽然列表 (list) 可以完成基本的数组功能&#xff0c;但它并不是真正的数组&#xff0c;而且在数据量较大时&#xff0c;使用列表的速度就会慢的让人难受。为此&#xff0c;Numpy 提供了真正的数组功能&#xff0c;以及对数据快速处理的函…

php如果实现日历的制作,教大家制作简单的php日历

最近的一个项目中&#xff0c;需要将数据用日历方式显示&#xff0c;网上有很多的JS插件&#xff0c;后面为了自己能有更大的控制权&#xff0c;决定自己制作一个日历显示。如下图所示&#xff1a;一、计算数据1、new一个Calendar类2、初始化两个下拉框中的数据&#xff0c;年份…

编程要养成的好习惯

1.- DRY: Don’t repeat yourself. DRY 是一个最简单的法则&#xff0c;也是最容易被理解的。但它也可能是最难被应用的&#xff08;因为要做到这样&#xff0c;我们需要在泛型设计上做相当的努力&#xff0c;这并不是一件容易的事&#xff09;。它意味着&#xff0c;当我们在…

flink整合java,Flink使用SideOutPut替换Split实现分流

基于apache flink的流处理实时模型44元包邮(需用券)去购买 >以前的数据分析项目(版本1.4.2)&#xff0c;对从Kafka读取的原始数据流&#xff0c;调用split接口实现分流.新项目决定使用Flink 1.7.2&#xff0c;使用split接口进行分流的时候&#xff0c;发现接口被标记为depra…