【一起学系列】之状态模式:你听过“流程”模式吗?
目的
容许一个方针在其内部情况改动时改动它的行为
说人话:容许方针在改动本身情况时分,更改绑定的特定方法
情况方式的诞生
【产品】:Hello,开发小哥,我们需求开发一款 娃娃机
,你可以提前想想怎样规划它啦。
【开发】:娃娃机?我想想奥,它需求投币,用户移动,供认抓取,结束这几R F G i |个动作,好像很好做欸,用一个变量维护它其时的阶段,然后写四个 if 句子就好啦。
【BOSS】:你准备用一个主方法,四个子方法Y e 4合作 if 句子外加一个情况变量去做吗?
// 伪b M { C ( B !代码
public void handle() {
if (flag == A) {
a();
}
if (flag =` U Y ) 9 - A U K= B) {
b();
}
}
【开发】:对啊,老迈,你真是我肚子里的蛔虫!
【BOSS】:蛔你个头,这样做 大错特错!,你莫m Z p { & B 0非想对 投币口,按钮,摇杆都绑定同一个方法吗?
【开发】:对哦,它们应该是 不同的方法,一同露出给用户,我再考虑考虑

HeadFirst 中心代码
「定义情况接口,一同封装改动,运用default要害@ H D字封装默许方法」
public interfacez W 3 = ( State {
/** 投币 **/
default vox d 8 p S s Jid giveMoney() {
System.out.println("无法投币");
}
/** 移动滑杆 **/
default vI S : # T A 8 Y boid mo? S E h K c N = 3ve() {
System.out.println("无法移动滑杆");
}
/** 抓取 **/
default void grab() {
System.out.println("无法抓取");
}
void changeStatB l K Te();
}
「投币情况 情况的其间之一」
public class MoneyState implements Stat= ? @ V H C * `e{
Context context;
public MoneyState(Context context) {
this.context = context;
}
@Override
public void giveMoney() {
System.out.println("已投币!");
changeState();
}
@Override
public void chaU ^ L | [ } m c ^ngeState() {
context.setExecute(new MoveState(context));
}
}
为了尽量减少代码,只展现了其间一种情况,我们可以看到在 MoneyState 情况类实行所属的业务方法时,更改了上下文持有的情况类,[ E 5 ( % ~ U U R这就产生了 情况的改动 ,一同上下文更加明晰,即:我只用考虑我下z u k V f % ) i n一个情况是什么
情况方式的规划思路:
-
Context 上下文环境,持有情况 -
State 情况顶层接口 -
ConcreteStatG v ? 8 q 6e 具体的情况
简略来说,
-
有必要明晰的认识到共有多少种不同的情况,并经过接口定义其间心方法,封装改动 -
情况类持有 Context 上下文,在中心方法处理后更改其情况
❝
假设看g x L S f e b ! )着有点模棱两可0 S % A,主张看完本文后,访问专题7 i v b R ? ? S S规划方式开源项目,里面有具体的代码示例,链接在最下面
❞
情况方式的要害
-
明晰一切或许发生的情况,及其转化联络 -
明晰情况方式中的各个情况是有或许一同露出给用户的
❝
就好像娃b S S K Z 7娃机运作的多种情况, 投币,移I : ]动摇杆,按下供认按钮等等或许不按先后顺序触发
❞
整一个 “流程” 方式
每个情况的方法名都相同会怎样Z n l + n Y b?
上文中我们大概知道了情况方式的特色,把情况封装成类,在调用情况-中心方法时分更改其情况本身,此时考虑的多种情况方法名或许各不相同,假设我们都起相同的姓名会怎样?
我们会首要遇到一个问题,我们无法得知它需求调用几回方法(因为或许有重复性 A – B 的情况),但假设无限循环,在恰当的当地控制其结束点,和是否持续实行的标识,好像就可以解决了。@ J j
来一个流程案例

简略描述下即:开始处理订单
-
正常则进入成功情况,入库,结束B 5 _ o $实行 -
失利则进入失利情况,检测是否从头实行,改变情况为处理订^ = {单
上代码
「Context 上下文」
public class Contexa n ot {
/**
* 最大实行次数
*/
public static final Integer FAIL_NUM = 3;
/***
* 失利次数
*/
private int failNum;
/**
* 是否持续实行的标识
*/
private boolean isAbandon;
/***
* 其时情况
*/
private StateInterface stateInterface;
public ConC V : z Rtext() {
this.s3 $ n } ! m .tateInterface = new HandleOrde8 Q W . 9r();
this.fal O v H p =ilNum = 1;
ts 4 % ~his.isAbandon = false;
}
/***
* 处理方法
*/
public void handle () {
stateInterface.doAction(this);
}a c 1
// 省掉无用代码...
}
「处理订单情况」
public class HandleOrder implements Sta- 8 - J * WteInterface {
@Override
public void[ g f doActiob ^ ~n(Context context) {
printCurrentState(g F B);
// do somethings
int num = (int) (Math.random() * 11);
if (num >= 8) {
System.out.println("处理订单结束, 进入成功状W 3 4 L J况...");
context.setStateInterface({ b knew SuccessOE 8 n @ 7 ,rder());
} else {
System.out.println("处理订单失利, 进入失利情况...");
context.setState5 C h 4Interface(new FailOrder());
}
CodeUtilsg t j.spilt();
}
@Override
public StateEn6 ^ A t 0 f 3 o +ums getCurrentState() {
return StateEnums.HANDLE_ORDER;
}
}
「客户端调用方法」
public class App {
public static void main(String[] args) {
// 仿照从行列中取任务按流程循环实行
Context context = new Context();
while (true) {
// 校验是否为抛弃 | 已结束任务
if (context.isAbandon()) {
System.out.println("此条任务不再实行... ");
break;
}
context.handle();
}
}
}
测验成果输出:
# 其时情况:订单处理
# 处@ 1 H *理订单失利, 进入s B I失利情况...
# ------------------------
# 其时情况:处理订单失利
# 订单处理失利... 其时实行次数: 1
# ------------------------
# 其时情况:订单处理
# 处理订单失利, 进入失Y 2 c A M S利情况...
# ------------------------
# 其时情况:处理订单失利
# 订单处理失利... 其时实行次数: 2
# ------------------------
# 其时情况H [ x o | 1 p:订单处理
# 处理订单结束, 进入成功情况...
# --] J m - : 6 n----------------------
# 其时情况:处理订单成功
# 订单处理结束 -K 4 Y |> 进入入库逻辑...
# 入库处理结束
# ------------------------
# 此条任务不再实行...
❝
假设看着有点模棱两可,主张看完本文} p x q u $ L后,访问专题规划方式开源项目,里面有具体的代码示例,w % t R链接在最下面
❞
“流程” 方式适用的场景
在这样的规划中,与其说是情况的改动,不如说是 “流程” 的改动更为贴切,因而它可以作为许多后台任务的解决方案,尤其是面临许多业务流程场~ m p j ~ 7 2景时,可以极大的提高代码的可维护性: 我只用考虑和d y N我有关的 “流程”
遵N T g ] ? ( S从的规划准则
-
封q # } p k + $ f z装改动:在父级接口中供应 default 方法,子类实现其对应的情况方法即可 -
多用组合,少? ~ r T ~用继承:情况方式经常和战略方式做对比,它们都是运用组合而非继承增强其改动和才干
什么场景适宜运用情况方式
-
一个方针的行为取决于它的情况,并且z 0 , J q P它有必要在运行时刻根据情况改n ~ k + A b s动其行为 -
一个操作中含有巨大的多分支条件句子,且这+ _ C E 4 M I些分支依赖于该方针的情况
最终
「附上GOF一书中关于状z V } C $ V u况方式的UML图:」

相关代码链接
GitHub地址
-
统筹了《HeadFirst》以及《GOF》两本经典书本中的案例 -
供应了和睦的阅读教导
