首页 理论教育 23种设计模式:状态模式解析

23种设计模式:状态模式解析

时间:2023-11-03 理论教育 版权反馈
【摘要】:第二十一章金融危机何时休——状态模式21.1金融危机何时休时间:1月6日地点:大B房间人物:大B,小A小A:“现在每天一打开电视、报纸,铺天盖地而来的全是这次‘愈演愈烈’的金融危机!”

23种设计模式:状态模式解析

第二十一章 金融危机何时休——状态模式

21.1 金融危机何时休

时间:1月6日  地点:大B房间  人物:大B,小A

小A:“现在每天一打开电视、报纸,铺天盖地而来的全是这次‘愈演愈烈’的金融危机!”

大B:“这次危机预计要到2009年上半年股市才会平缓,世界经济要恢复则要数年左右,中国大概3年左右,美国可能需十数年。此次危机已造成世界金融也蒸发了35万亿美元左右。全球约有上千万人在此次危机中失业,世界各国投入的救市资金已经超过3万亿美元,将来会更多。”

小A:“是啊!中国股市缩水60%市值蒸发20万亿RMB,实体经济也开始大规模受损,房产市场冷淡,中小企业艰难度日,大型企业融资困难,消费市场缩减,继而冲击其他与以上有关的每个行业,迫使中国政府决定在2010年左右投入4万亿RBM用于救市和刺激消费,但总体上对中国的影响并不大。”

大B:“这是因为中国前三季度的数据显示中国还是保持了较高的增长率,社会固定资产增加值超过了去年同期水平发展虽然有所放缓,但经济发展水品还是很高的。虽然金融不景气但是中国金融资产的占有国民经济总量中很少。同时中国自身的消费市场巨大,我们的正常生活不会受太大影响。”

小A:“这是因为中国政府的应对政策,除了拿出4万亿用于就是之外,银行将进行数次降息,同时对陷入困境的中小企提供贷款,和减税政策,为大型企业提供融资渠道。”

大B:“追寻此次危机的根源是现有的金融体制存在严重缺陷,所以这次危机过后肯定会制定新的金融经济秩序。而中国将在其中发挥主导作用,中国很可能借助此次千载难逢的机遇,美欧经济不景气,美元这一世界货币疲软的机遇崛起世界经济新格局将因此形成。”

小A:“现在大家都在相互疑问:金融危机何时休啊?”

21.2 状态模式

金融危机就是我们所说状态模式。

小A:“什么是状态模式?”

大B:“允许一个对象在其内部状态改变时改变它的行为。这个对象看起来似乎修改了它的类。看起来,状态模式好像是神通广大——居然能够‘修改自身的类’!能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些可能发生的外部情况全部考虑到,使用if else 语句来进行代码响应选择。但是这种方法对于复杂一点的状态判断,就会显得杂乱无章,容易产生错误;而且增加一个新的状态将会带来大量的修改。这个时候‘能够修改自身’的状态模式的引入也许是个不错的主意。”

21.3 状态模式的角色

小A:“状态模式由哪些角色组成呐?”

大B:“状态模式可以有效的替换充满在程序中的if else语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们。状态模式是由下面几种角色组成:1、使用环境(Context)角色:客户程序是通过它来满足自己的需求。它定义了客户程序需要的接口;并且维护一个具体状态角色的实例,这个实例来决定当前的状态。 2、状态(State)角色:定义一个接口以封装与使用环境角色的一个特定状态相关的行为。3、具体状态(Concrete State)角色:实现状态角色定义的接口。结构非常简单也与策略模式非常相似。”

参考图21-1状态模式类图

图21-1 状态模式类图

21.4 状态模式的特征

小A:“状态模式都有些什么特征?”

大B:“抽象状态角(State)色:定义一个接口,用以封装语境(Context)对象的一个特定的状态所对应的行为。具体状态(ConcreteState)角色:一个具体状态类,实现了语境(Context)对象的一个状态所对应的行为。语境(Context)角色:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例,这个具体状态类的实例给出此环境对象的现有状态。通过使用多态,可以动态地改变语境(Context)对象的属性State的内容,使其从指向一个具体状态类到指向另外一个具体状态类,从而改变语境(Context)对象的行为。”

21.5 状态模式优点

小A:“状态模式有什么优点?”

大B:“1、封装转换过程,也就是转换规则。2、枚举可能的状态,因此,需要事先确定状态种类。”

21.6 状态模式实质

小A:“状态模式的实质是什么?”

大B:“使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如何状态变化,这些是由状态机等内部实现。这是一种Event-condition-State,状态模式封装了condition-State部分。每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。”

小A:“都有些什么方法实现状态转换?”

大B:“一个在每个状态实现next(),指定下一个状态;还有一种方法,设定一个StateOwner,在StateOwner设定stateEnter状态进入和stateExit状态退出行为。状态从一个方面说明了流程,流程是随时间而改变,状态是截取流程某个时间片。”

21.7 状态模式和策略模式的比较

小A:“怎样去比较状态模式和策略模式?”

大B:“在状态模式中,状态的变迁是由对象的内部条件决定,外界只需关心其接口,不必关心其状态对象的创建和转化;而策略模式里,采取何种策略由外部条件(C)决定。Strategy模式与State模式的结构形式几乎完全一样。但它们的应用场景(目的)却不一样,State模式重在强调对象内部状态的变化改变对象的行为,Strategy模式重在外部对策略的选择,策略的选择由外部条件决定,也就是说算法的动态的切换。但由于它们的结构是如此的相似,我们可以认为状态模式是完全封装且自修改的策略模式。”

小A:“公认的事实:策略和状态模式是孪生兄弟。”(www.xing528.com)

大B:“就像你所知道的,策略模式通过可互换的算法规则来创建非常成功的业务模式。不管怎么样,状态以非常高尚的方式帮助对象学习通过他们内部的状态来控制他们的行为。他总是无意中告诉他的对象客户,‘跟着我重复就行了,我足够好,我足够聪明…’”

21.8 何时使用状态模式?

小A:“什么时候使用状态模式?”

大B:“State模式在实际使用中比较多,适合‘状态的切换’.因为我们经常会使用If elseif else 进行状态切换,如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了。不只是根据状态,也有根据属性。如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State 。”

21.9 是否使用状态模式?

小A:“要怎么去决定是否使用状态模式?”

大B:“在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度。这里要说的是‘开关切换状态’和‘一般的状态判断’是有一些区别的,‘ 一般的状态判断’也是有 if..elseif结构。”

例如:

大B:“这是一个‘一般的状态判断’,state值的不同是根据which变量来决定的,which和state没有关系。”

如果改成:

大B:“这就是‘开关切换状态’,是将state的状态从‘hello’切换到‘hi’,再切换到‘bye’;在切换到‘hello’,好象一个旋转开关,这种状态改变就可以使用State模式了。如果单纯有上面一种将‘hello’-->‘hi’-->‘bye’-->‘hello’这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了。”

请看下例:

大B:“在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它。另外注意: state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂。”

例如:银行帐户,经常会在Open 状态和Close状态间转换。

例如:经典的TcpConnection ,Tcp的状态有创建、侦听、关闭三个,并且反复转换,其创建、侦听、关闭的具体行为不是简单一两句就能完成的,适合使用State 。

例如:信箱POP帐号,会有四种状态,start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的.适合使用State 。

例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State 。如具体绘图程序,用户可以选择不同工具绘制方框、直线、曲线,这种状态切换可以使用State 。

21.10 如何使用状态模式?

小A:“如何使用状态模式?”

大B:“状态模式可以允许客户端改变状态的转换行为,而状态机则是能够自动改变状态,状态机是一个比较独立的而且复杂的机制,具体可参考一个状态机开源项目:

状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如政府OA中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状态的使用者。在网络游戏中,一个游戏活动存在开始;开玩;正在玩;输赢等各种状态,使用状态模式就可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游戏架构功能实现起到决定的主导作用。

State需要两种类型实体参与:1、state manager 状态管理器,就是开关,如上面例子的Context实际就是一个state manager在state manager中有对状态的切换动作。2、用抽象类或接口实现的父类,不同状态就是继承这个父类的不同子类。”

以上面的Context为例。我们要修改它,建立两个类型的实体。

第一步:

首先建立一个父类:

父类中的方法要对应state manager中的开关行为,在state manager中这个例子就是Context中,有两个开关动作push推和pull拉。那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull();同时还需要一个获取push或pull结果的方法getcolor()

下面是具体子类的实现:

同样 其他状态的子类实现如blue一样。

第二步:

要重新改写State manager 也就是本例的Context:

至此,我们也就实现了State的refactorying过程。

以上只是相当简单的一个实例,在实际应用中,handlepush或handelpull的处理是复杂的。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈