设计模式之状态模式

情景:有一个自动投币的糖果机。它有以下几种状态(每个圆圈代表一个状态):

如果用常量值来定义几个变量

SOLD_OUT = 0 NO_QUARTER = 1 HAS_QUARTER = 2 SOLD = 3<span style="color: #0000ff;">int state = SOLD_OUT;

这样状态变化就可以写成:

(state == (state ==

每一个动作都要先判断状态,改后再决定反馈以及下一个状态是什么。

虽然可以实现要求,但是当出现新的状态的时候,很不利于扩展。

我们把状态变成一个类,把不同的状态封装在各自的类中,然后在动作发生时委托给当前状态。

首先,定义状态接口

然后定义各种状态

<div class="cnblogs_code" onclick="cnblogs_code_show('026e1670-0ced-45f5-9619-b0d2e08d203e')">
<img id="code_img_closed_026e1670-0ced-45f5-9619-b0d2e08d203e" class="code_img_closed" src="https://www.jb51.cc/res/2019/02-05/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt=""><img id="code_img_opened_026e1670-0ced-45f5-9619-b0d2e08d203e" class="code_img_opened" style="display: none;" onclick="cnblogs_code_hide('026e1670-0ced-45f5-9619-b0d2e08d203e',event)" src="https://www.jb51.cc/res/2019/02-05/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt=""><div id="cnblogs_code_open_026e1670-0ced-45f5-9619-b0d2e08d203e" class="cnblogs_code_hide">

  HasQuarterState GumballMachine gumballMachine;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; HasQuarterState(GumballMachine gumballMachine) {
    </span><span style="color: #0000ff;"&gt;this</span>.gumballMachine =<span style="color: #000000;"&gt; gumballMachine;
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; insertQuarter() {
    System.out.println(</span>"You can't insert another quater"<span style="color: #000000;"&gt;);        
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; ejectQuarter() {
    System.out.println(</span>"Quarter returned"<span style="color: #000000;"&gt;);
    gumballMachine.setState(gumballMachine.getNoQuarterState());
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; turnCrank() {
    System.out.println(</span>"You turned..."<span style="color: #000000;"&gt;);
    gumballMachine.setState(gumballMachine.getSoldState());
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; dispense() {
    System.out.println(</span>"No gumball dispensed"<span style="color: #000000;"&gt;);
}

}

<div class="cnblogs_code" onclick="cnblogs_code_show('b32320a8-0f59-4338-9d16-ea46e723673b')">
<img id="code_img_closed_b32320a8-0f59-4338-9d16-ea46e723673b" class="code_img_closed" src="https://www.jb51.cc/res/2019/02-05/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt=""><img id="code_img_opened_b32320a8-0f59-4338-9d16-ea46e723673b" class="code_img_opened" style="display: none;" onclick="cnblogs_code_hide('b32320a8-0f59-4338-9d16-ea46e723673b',event)" src="https://www.jb51.cc/res/2019/02-05/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt=""><div id="cnblogs_code_open_b32320a8-0f59-4338-9d16-ea46e723673b" class="cnblogs_code_hide">

  SoldOutState GumballMachine gumballMachine;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; SoldOutState(GumballMachine gumballMachine) {
    </span><span style="color: #0000ff;"&gt;this</span>.gumballMachine =<span style="color: #000000;"&gt; gumballMachine;
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; insertQuarter() {
    System.out.println(</span>"You can't insert a quarter,the machine is sold out"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; ejectQuarter() {
    System.out.println(</span>"You can't eject,you haven't inserted a quarter yet"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; turnCrank() {
    System.out.println(</span>"You turned,but there are no gumballs"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; dispense() {
    System.out.println(</span>"No gumball dispensed"<span style="color: #000000;"&gt;);
}

}

<div class="cnblogs_code" onclick="cnblogs_code_show('fdcdb9e7-168f-4423-92dd-31d604827d7e')">
<img id="code_img_closed_fdcdb9e7-168f-4423-92dd-31d604827d7e" class="code_img_closed" src="https://www.jb51.cc/res/2019/02-05/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt=""><img id="code_img_opened_fdcdb9e7-168f-4423-92dd-31d604827d7e" class="code_img_opened" style="display: none;" onclick="cnblogs_code_hide('fdcdb9e7-168f-4423-92dd-31d604827d7e',event)" src="https://www.jb51.cc/res/2019/02-05/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt=""><div id="cnblogs_code_open_fdcdb9e7-168f-4423-92dd-31d604827d7e" class="cnblogs_code_hide">

  SoldState GumballMachine gumballMachine;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; SoldState(GumballMachine gumballMachine) {
    </span><span style="color: #0000ff;"&gt;this</span>.gumballMachine =<span style="color: #000000;"&gt; gumballMachine;
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; insertQuarter() {
    System.out.println(</span>"Please wait,we're already giving you a gumball"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; ejectQuarter() {
    System.out.println(</span>"Sorry,you already turned the crank"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; turnCrank() {
    System.out.println(</span>"Turning twice doesn't get you another gumball!"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; dispense() {
    gumballMachine.releaseBall();
    </span><span style="color: #0000ff;"&gt;if</span> (gumballMachine.getCount() > 0<span style="color: #000000;"&gt;) {
        gumballMachine.setState(gumballMachine.getNoQuarterState());
    } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; {
        System.out.println(</span>"Oops,out of gumballs!"<span style="color: #000000;"&gt;);
        gumballMachine.setState(gumballMachine.getSoldOutState());
    }
}

}

最后写一下糖果机

State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State state </span>=<span style="color: #000000;"&gt; soldOutState; </span><span style="color: #0000ff;"&gt;int</span> count = 0<span style="color: #000000;"&gt;; </span><span style="color: #0000ff;"&gt;public</span> GumballMachine(<span style="color: #0000ff;"&gt;int</span><span style="color: #000000;"&gt; numberGumballs) { soldOutState </span>= <span style="color: #0000ff;"&gt;new</span> SoldOutState(<span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;); noQuarterState </span>= <span style="color: #0000ff;"&gt;new</span> NoQuarterState(<span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;); hasQuarterState </span>= <span style="color: #0000ff;"&gt;new</span> HasQuarterState(<span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;); soldState </span>= <span style="color: #0000ff;"&gt;new</span> SoldState(<span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;); count </span>=<span style="color: #000000;"&gt; numberGumballs; </span><span style="color: #0000ff;"&gt;if</span> (numberGumballs > 0<span style="color: #000000;"&gt;) { state </span>=<span style="color: #000000;"&gt; noQuarterState; } } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; insertQuarter() { state.insertQuarter(); } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; ejectQuarter() { state.ejectQuarter(); } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; turnCrank() { state.turnCrank(); state.dispense(); } </span><span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; setState(State state) { </span><span style="color: #0000ff;"&gt;this</span>.state =<span style="color: #000000;"&gt; state; } </span><span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; releaseBall() { System.out.println(</span>"A gumball comes rolling out the slot..."<span style="color: #000000;"&gt;); </span><span style="color: #0000ff;"&gt;if</span> (count != 0<span style="color: #000000;"&gt;) { count </span>-= 1<span style="color: #000000;"&gt;; } } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;int</span><span style="color: #000000;"&gt; getCount() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; count; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; State getSoldOutState() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; soldOutState; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; State getNoQuarterState() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; noQuarterState; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; State getHasQuarterState() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; hasQuarterState; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; State getSoldState() { </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; soldState; } </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; String toString() { </span><span style="color: #0000ff;"&gt;return</span> "\nMighty Gumball,Inc\n" + "Inventory: " +<span style="color: #000000;"&gt; count </span>+ " gumballs\n"<span style="color: #000000;"&gt;; }

}

测试类:

将每一个状态局部化到它自己的类中。将容易产生问题的if语句删除,方便日后的维护。

这样,每一个状态“对修改关闭”,糖果机“对扩展开放”

状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了它的类。

类图:

现在我们改变需求,希望有10%的概率中奖,也就是投一个币,获得两个糖果。

我们只需要添加一个新的状态类。

WinnerState GumballMachine gumballMachine; </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; WinnerState(GumballMachine gumballMachine) { </span><span style="color: #0000ff;"&gt;this</span>.gumballMachine =<span style="color: #000000;"&gt; gumballMachine; } @Override </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; insertQuarter() { System.out.println(</span>"Please wait,you already turned the crank"<span style="color: #000000;"&gt;); } @Override </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; turnCrank() { System.out.println(</span>"Turning twice doesn't get you another gumball!"<span style="color: #000000;"&gt;); } @Override </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; dispense() { System.out.println(</span>"YOU'RE A WINNER! YOU GET TWO GUMBALLS FOR YOUR QUARTERS"<span style="color: #000000;"&gt;); gumballMachine.releaseBall(); </span><span style="color: #0000ff;"&gt;if</span> (gumballMachine.getCount() == 0<span style="color: #000000;"&gt;) { gumballMachine.setState(gumballMachine.getSoldOutState()); } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { gumballMachine.releaseBall(); </span><span style="color: #0000ff;"&gt;if</span> (gumballMachine.getCount() > 0<span style="color: #000000;"&gt;) { gumballMachine.setState(gumballMachine.getNoQuarterState()); } </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; { System.out.println(</span>"Oops,out of gumballs!"<span style="color: #000000;"&gt;); gumballMachine.setState(gumballMachine.getSoldOutState()); } } }

}

在HasQuarterState中有几率跳到WinnerState状态:

HasQuarterState GumballMachine gumballMachine; Random randomWinner </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; Random(System.currentTimeMillis()); </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; ....</span>

<span style="color: #000000;">
@Override
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> turnCrank() {
System.out.println("You turned..."<span style="color: #000000;">);
<span style="color: #0000ff;">int winner = randomWinner.nextInt(10<span style="color: #000000;">);
<span style="color: #0000ff;">if (winner == 0 && (gumballMachine.getCount() > 1<span style="color: #000000;">)) {
gumballMachine.setState(gumballMachine.getWinnerState());
} <span style="color: #0000ff;">else<span style="color: #000000;"> {
gumballMachine.setState(gumballMachine.getSoldState());
}
}

</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; ....</span>

<span style="color: #000000;">
}

记得在糖果机类中添加一个WinnerState状态类,这个新的需求就实现了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结