欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式之十 状态模式

程序员文章站 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()调用的判断条件。

 

 

 

 

 

 

设计原则

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程

为交互对象之间的松耦合设计而努力

类应该对扩展开放,对修改关闭

依赖抽象,不要依赖具体类

只和朋友交谈

别找我,我会找你

类应该只有一个改变的理由

 

总结

状态模式允许一个对象基于内部状态而拥有不同的行为。

通过将每一个状态封装进一个类,我们以后需要做的任何改变局部化了。

使用状态模式通常会导致设计中的类的数目的大量增加。