首页 > 经验记录 > Pattern

我总感觉网上写的和我写的不是同一个模式似的…

我这个状态切换的流畅的一批,而且外部调用者完全与其状态的变换隔离。

也完美符合迪米特法则,新增状态原有代码逻辑一丝都不用修改。

就是实现起来略复杂

 

核心:

  • 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

 

结构:

-Context环境类

  • 环境类中维护一个State对象,他是定义了当前的状态

-State抽象状态类

-ConcreteState具体状态类

  • 每一个类封装了该状态对应的行为

 

简单点说:

状态模式封装的非常好,状态的变更引起了行为的变更,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换,从外部看起来就好像这个对象对应的类发生了改变一样。

 

下面是我写的代码,用酒店的房间作为例子。

其房间有三种状态,1:空闲、2:预定、3:已入住,我将以这三种状态的变换来演示状态模式的奥妙

 

State 接口

 

 

Context环境类:

 

说明:

到这就需要说明一下。这个状态和环境是一个你中有我,我中有你的结构。可以看到他们都有一个 Set方法 ,这个方法就是用于动态的变换。会经常用到。

状态中有环境,是因为状态变更时需要操作环境,将环境所维护的状态改变。状态变更时如何操作环境?你将在下面几个子类中看到

环境中有状态,环境为何叫做环境?自然是代表状态所处的环境,客户端进行状态切换时,所面对的就是该环境对象。即调用方法依赖环境而不是状态。

 

3种房间的状态:

 

在状态变更时,会进行两步处理:

1、将环境类 Context 维护的状态改变为切换后的状态

2、触发该状态的方法

 

假设现在客户端拥有一个状态为【空闲】的环境,那么,在他调用环境的 booked() 方法时,会触发如下现象:

1、环境所维护的状态对象由【空闲】变为【预定】

2、预定对象的  booked() 方法被调用,打印出”已预订”。

此时环境已经为预定状态。

 

下面看我使用一个客户端演示切换状态:

 

System.out:

已预订
退房,行吧
空闲状态~
没预定你住你马呢?
已预订
已入住
退房,行吧
空闲状态~

 

看看,是不是这个客户端只用管切换状态就对了,其余的都与其无关?

观察我写的代码,可以发现状态模式可扩展性极强,若想新增一个状态,源代码逻辑一点都不需要变动。只需要在新增一个状态类并且在接口和环境中新增对应的方法和属性即可。真正的对修改关闭对扩展开放。

 

这个模式实现起来还是比较抽象的。若是想在实际项目中将其优势完美发挥,估计得需要一点编码内力才行。我也不确定我能否将其完美运用。估计机会也不多。

不过,状态模式确实使我有种:原来代码还能这么玩? 的感觉,真的是太灵性了。

 

 

阅读全文

模板方法模式是编程中经常用到到的模式。它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。

核心:处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,可以将该节点的代码实现转移给子类完成。即:处理步骤父类定义好,具体实现延迟到子类中定义,由父类进行整个过程的控制。

 

使用场景:实现一个算法时,整体步骤很固定,但是某些部分易变。易变部分可以抽象出来,供子类实现。

 

比如一个场景:

玩氪金手游充钱抽卡的流程。可以确定的是

第一步:打开氪金界面。

第二步:选择氪金。

第三步:选择支付方式。

最后:抽奖。

 

假设其他流程均为固定,而其中只有选择支付方式这一点可能会有所变化。比如可以用支付宝、微信等等支付。

那么要实现这种需求,每种方式都重复进行一遍编写的话代码太多,过于丑陋。

这时即可使用模板方法模式,将其固定的流程定死,并将选择支付方式声明为抽象,强制子类实现。

 

代码实现:

氪金的模板方法,可以看见我实现了除【选择支付方式】以外其余所有的方法。并且将流程控制在内部。

子类的权限只够修改除了执行整个氪金流程以外的方法。并且需要强制实现选择支付方式的方法。

 

实现其抽象方法的具体类以及客户端调用者:

若实现模板方法的子类并不复杂的话可考虑将其写成匿名内部类。若算法特别复杂并且需要实现的抽象的方法不止一个,那还是老老实实写个子类继承比较好。