设计模式之十 状态模式
程序员文章站
2022-06-17 17:10:38
...
状态模式
目录
目录
定义
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
例子
我们使用《Head First 设计模式》中的糖果机例子:
糖果机有NoQuarter、HasQuarter、Sold、SoldOut等状态,当然,我们后期可以根据需求加入Winner状态。
首先,让我们创建一个接口,让所有的状态都必须实现这个接口:
/**
* 状态类
* @author Kwin
*
*/
public interface State {
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispense();
}
我们实现下面四个状态,后面添加一个赢家状态:
/**
* 未投硬币状态
* @author Kwin
*
*/
public class NoQuarterState implements State {
private GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("你插入了一枚硬币");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("没钱,你不能退钱");
}
@Override
public void turnCrank() {
System.out.println("没钱还想要糖果?美得你");
}
@Override
public void dispense() {
System.out.println("你要先付钱");
}
}
/**
* 已投硬币状态
* @author Kwin
*
*/
public class HasQuarterState implements State {
Random randomWinner = new Random(System.currentTimeMillis());
private GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("机子里已经插过钱了");
}
@Override
public void ejectQuarter() {
System.out.println("退钱成功");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("等待出货");
int winner = randomWinner.nextInt(10);
if(winner == 0 && gumballMachine.getCount() > 1) {
gumballMachine.setState(gumballMachine.getWinnerState());
}else {
gumballMachine.setState(gumballMachine.getSoldState());
}
}
@Override
public void dispense() {
System.out.println("没有糖果发放");
}
}
/**
* 售光状态
* @author Kwin
*
*/
public class SoldOutState implements State {
private GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("别塞,没糖果了");
}
@Override
public void ejectQuarter() {
System.out.println("哟呵,想诈骗啊");
}
@Override
public void turnCrank() {
System.out.println("说了,没糖果了");
}
@Override
public void dispense() {
System.out.println("没糖果了");
}
}
/**
* 销售状态
* @author Kwin
*
*/
public class SoldState implements State {
private GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("请等待,正在出货中");
}
@Override
public void ejectQuarter() {
System.out.println("抱歉,正在出货中");
}
@Override
public void turnCrank() {
System.out.println("你想出两次货?美得你");
}
@Override
public void dispense() {
gumballMachine.releaseBall();
if(gumballMachine.getCount() >0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("卖完啦!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
/**
* 赢家状态
* @author Kwin
*
*/
public class WinnerState implements State {
private GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("请等待,正在出货中");
}
@Override
public void ejectQuarter() {
System.out.println("抱歉,正在出货中");
}
@Override
public void turnCrank() {
System.out.println("你想出两次货?美得你");
}
@Override
public void dispense() {
gumballMachine.releaseBall();
if(gumballMachine.getCount() > 0) {
gumballMachine.releaseBall();
if(gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
gumballMachine.setState(gumballMachine.getSoldOutState());
}
} else {
System.out.println("卖完啦!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
让我们测试下我们的代码吧
/**
* 测试代码
* @author Kwin
*
*/
public class GumballMachineTestDriver {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(10);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.ejectQuarter();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}
}
测试结果:
上面的代码还有很多改进的地方,比如:可以把State接口改写成抽象类,把每个方法的默认行为放在其中,并把Context上下文的注入放进其中。
despense()方法一直被调用,我们可以让turnCrank()返回一个布尔值作为对despense()调用的判断条件。
设计原则
封装变化
多用组合,少用继承
针对接口编程,不针对实现编程
为交互对象之间的松耦合设计而努力
类应该对扩展开放,对修改关闭
依赖抽象,不要依赖具体类
只和朋友交谈
别找我,我会找你
类应该只有一个改变的理由
总结
状态模式允许一个对象基于内部状态而拥有不同的行为。
通过将每一个状态封装进一个类,我们以后需要做的任何改变局部化了。
使用状态模式通常会导致设计中的类的数目的大量增加。
上一篇: ANT 压缩(去掉空格/注释)JS文件可提高js运行速度
下一篇: RHEL6上课笔记之acl