1.意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
2.结构
Context(上下文)定义客户感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义当前状态。
State(状态)定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState(具体状态子类)每个子类实现与Context的一个状态相关的行为。
3.适用性:
一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象独立变化。
4.常见案例:会员等级升级
代码案例:
某航空公司的会员积分系统将其会员划分为:普卡(Basic)、银卡(Silver)和金卡(Gold)三个等级。非会员(NonMember)可以申请成为普卡会员。会员的等级根据其一年内累积的里程数进行调整。描述会员等级调整的状态图如下图所示。现采用状态(State)模式实现上述场景。
软件设计师考试2018年下半年下午题第6题
class FrequentFlyer{
CState state;
double flyMiles;
public FrequentFlyer() {
state = new CBasic("普卡会员");
flyMiles = 0;
setState(state);
}
public void setState(CState state){
this.state = state;
}
public void travel(int miles){
double bonusMiles = state.travel(miles,this);
flyMiles = flyMiles + bonusMiles;
}
}
abstract class CState{
public String name;
public int flyMiles;
public abstract double travel(int miles, FrequentFlyer context);
}
class CNoCustomer extends CState{//非会员
public CNoCustomer(String name){
this.name=name;
}
@Override
public double travel(int miles, FrequentFlyer context) {
System.out.println("Your travel will not account for points");
return 0;//不累积里程数
}
}
class CBasic extends CState{//普卡会员
public CBasic(String name){
this.name=name;
}
@Override
public double travel(int miles, FrequentFlyer context) {
if(context.flyMiles>=25000 && context.flyMiles<50000){
context.setState(new CSilver("银卡会员"));//升级为银卡会员
}
if(context.flyMiles>=50000){
context.setState(new CGold("金卡会员"));//升级为金卡会员
}
System.out.println("Your travel will account for points");
return miles;
}
}
class CSilver extends CState{//银卡会员
public CSilver(String name){
this.name=name;
}
@Override
public double travel(int miles, FrequentFlyer context) {
if(context.flyMiles>=50000){
context.setState(new CGold("金卡会员"));//升级为金卡会员
}
if(context.flyMiles<=25000){
context.setState(new CBasic("普卡会员"));//降级为普卡会员
}
System.out.println("Your travel will account for 1.25 times of points");
return miles + 0.25*miles;//累积里程数
}
}
class CGold extends CState{//金卡会员
public CGold(String name){
this.name=name;
}
@Override
public double travel(int miles, FrequentFlyer context) {
if(context.flyMiles>=25000 && context.flyMiles<50000){
context.setState(new CSilver("银卡会员"));//降级为银卡会员
}
if(context.flyMiles<=25000){
context.setState(new CBasic("普卡会员"));//降级为普卡会员
}
System.out.println("Your travel will account for 1.5 times of points");
return miles + 0.5*miles;//累积里程数
}
}
public class State {
public static void main(String[] args) {
FrequentFlyer frequentFlyer0 = new FrequentFlyer();//普卡
frequentFlyer0.setState(new CNoCustomer("非会员"));
frequentFlyer0.travel(6000);
System.out.println("里程数:"+frequentFlyer0.flyMiles+",会员等级:"+frequentFlyer0.state.name);
FrequentFlyer frequentFlyer = new FrequentFlyer();//普卡
frequentFlyer.travel(26000);
System.out.println("里程数:"+frequentFlyer.flyMiles+",会员等级:"+frequentFlyer.state.name);
frequentFlyer.travel(26000);//累积里程数,升级成银卡
System.out.println("里程数:"+frequentFlyer.flyMiles+",会员等级:"+frequentFlyer.state.name);
frequentFlyer.travel(26000);//累积0.25倍里程数,升级成金卡
System.out.println("里程数:"+frequentFlyer.flyMiles+",会员等级:"+frequentFlyer.state.name);
frequentFlyer.travel(26000);//累积0.5倍里程数
System.out.println("里程数:"+frequentFlyer.flyMiles+",会员等级:"+frequentFlyer.state.name);
}
}
运行结果: