介绍
- 状态模式 (State pattern): 它主要是用来解决对象在多种状态之间的转换,需要对外输出不同的行为的问题,状态和行为是一一对应的,状态之间可以互相转换。
- 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来是改变了其他类。
- Context : 为环境角色,用于维护一个ConcreteState子类的实例,这个实例定义当前的状态。
- State : 为抽象状态角色,定义一个接口以封装与Context的一个特定接口状态相关的行为。
- ConcreateState : 是具体状态角色,每一个子类实现一个与Context的一个状态相关的行为。
案例
抽奖活动:
- 假如每参加一次这个活动要扣除50积分,中奖概率是10%
- 奖品数量固定,抽完就不能抽奖
- 活动又四个状态:可以抽奖、不能抽奖、发放奖品和奖品已领完
创建 RaffleActivity 类 相当于状态模式中的 Context
public class RaffleActivity {
State state;
int count = 0;
State noRaffleState = new NoRaffleState(this);
State canRaffleState = new CanRaffleState(this);
State dispenseState = new DispenseState(this);
State dispenseOutState = new DispenseOutState(this);
public RaffleActivity(int count) {
this.state = getNoRaffleState();
this.count = count;
}
public void debuctMoney(){
state.deductMoney();
}
public void raffle(){
if(state.raffle()){
state.dispensePrize();
}
}
public int getCount(){
int curCount = count;
count-- ;
return curCount;
}
public void setCount(int COunt){
this.count = count;
}
public void setNoRaffleState(State noRaffleState) {
this.noRaffleState = noRaffleState;
}
State getNoRaffleState() {
return noRaffleState;
}
public State getCanRaffleState() {
return canRaffleState;
}
public void setCanRaffleState(State canRaffleState) {
this.canRaffleState = canRaffleState;
}
public State getDispenseState() {
return dispenseState;
}
public void setDispenseState(State dispenseState) {
this.dispenseState = dispenseState;
}
public State getDispenseOutState() {
return dispenseOutState;
}
public void setDispenseOutState(State dispenseOutState) {
this.dispenseOutState = dispenseOutState;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
创建抽象接口
public abstract class State {
/**
* 扣除积分
*/
public abstract void deductMoney();
/**
* 是否抽中奖品
*/
public abstract boolean raffle();
/**
* 发放奖品
*/
public abstract void dispensePrize();
}
创建 初始化抽奖活动 NoRaffleState 类继承 State
public class NoRaffleState extends State{
//初始化活动引用
RaffleActivity raffleActivity;
public NoRaffleState(RaffleActivity raffleActivity) {
this.raffleActivity = raffleActivity;
}
@Override
public void deductMoney() {
System.out.println("扣除50积分可以抽奖");
raffleActivity.setState(raffleActivity.getCanRaffleState());
}
@Override
public boolean raffle() {
System.out.println("输入积分才能抽奖");
return false;
}
@Override
public void dispensePrize() {
System.out.println("当前状态不能发放奖品");
}
}
创建 正在抽奖活动 CanRaffleState 类继承 State
public class CanRaffleState extends State{
//初始化活动引用
RaffleActivity raffleActivity;
public CanRaffleState(RaffleActivity raffleActivity) {
this.raffleActivity = raffleActivity;
}
@Override
public void deductMoney() {
System.out.println("已经扣取过积分");
}
@Override
public boolean raffle() {
System.out.println("正在抽奖 ……");
Random r = new Random();
int num = r.nextInt(10);
if(num == 0){
System.out.println("中奖了");
raffleActivity.setState(raffleActivity.getDispenseState());
//发放奖品
return true;
}else {
System.out.println("很遗憾,没有中奖");
raffleActivity.setState(raffleActivity.getNoRaffleState());
return false;
}
}
@Override
public void dispensePrize() {
System.out.println("不能发放奖品");
}
}
创建 分发抽奖活动 DispenseState 类继承 State
public class DispenseState extends State{
//初始化活动引用
RaffleActivity raffleActivity;
public DispenseState(RaffleActivity raffleActivity) {
this.raffleActivity = raffleActivity;
}
@Override
public void deductMoney() {
System.out.println("不能扣除积分");
}
@Override
public boolean raffle() {
System.out.println("不能抽奖");
return false;
}
@Override
public void dispensePrize() {
if (raffleActivity.getCount() > 0){
raffleActivity.setState(raffleActivity.getNoRaffleState());
}else{
System.out.println("奖品发完了");
raffleActivity.setState(raffleActivity.getDispenseState());
}
}
}
创建 抽奖活动分发完成 DispenseOutState 类继承 State
public class DispenseOutState extends State{
//初始化活动引用
RaffleActivity raffleActivity;
public DispenseOutState(RaffleActivity raffleActivity) {
this.raffleActivity = raffleActivity;
}
@Override
public void deductMoney() {
System.out.println("奖品发送完了,下次参加");
}
@Override
public boolean raffle() {
System.out.println("奖品发送完了,下次参加");
return false;
}
@Override
public void dispensePrize() {
System.out.println("奖品发送完了,下次参加");
}
}
客户端
public class Client {
public static void main(String[] args) {
RaffleActivity raffleActivity = new RaffleActivity(1);
for (int i = 1; i < 10; i++) {
System.out.println("----------第" +i+"次抽奖---------");
//扣积分
raffleActivity.debuctMoney();
raffleActivity.raffle();
}
}
}
优点和缺点
优点:
1)结构清晰,避免了过多的switch…case或if…else语句的使用
2)很好的体现了开闭原则和单一职责原则,想要增加状态就增加子类,想要修改状态就修改子类即可
3)封装性非常好,状态变化放置到了类的内部来实现,外部调用不需要知道类内部如何实现状态和行为的变换
缺点:
1)子类会太多,也即类膨胀
适用场景:
1) 一行为随状态改变而改变的场景 如 : 一日从早到晚自身的状态,比如工作状态、学习状态等等
2) 条件、分支判断语句的替代者
github Demo地址 : ~~~传送门~~~
个人博客地址:http://blog.yanxiaolong.cn/