简介
优点:
1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对象之间耦合度高,破坏"开闭原则"。
作者:秃头的路上
链接:https://www.jianshu.com/p/e335799a5a0b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
角色与理解
状态模式共分为三种角色:
Context(上下文环境):将自身的状态与行为分离出去,封装成状态类,持有抽象状态类的引用,根据自身属性变换更换具体状态类。
State(抽象状态类):具体状态类的抽象,可以持有上下文环境的引用来更换状态。
Concrete State(具体状态类):实现不同状态下的不同行为。
上下文环境引用抽象状态类完成行为的调用,状态类的状态变化可以有上下文环境处理,也可以由状态类处理。
状态类可以共享,像开关对象一样,可以被多个上下文环境引用。
流程图
本案例使用用户进行存取金额的行为,用户的账号状态作为展示
代码展示
账户类Account
package com.nj.boke.state;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 账户
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
/**
* 余额
*/
private double balance;
/**
* 透支额度
*/
private double amount;
/**
* 账户状态
*/
private Accountstate accountstate;
/**
* 存钱
*/
public void cq(double money){
this.getAccountstate().cq(money);
}
/**
* 取钱
*/
public void qq(double money){
this.getAccountstate().qq(money);
}
/**
* 查看状态
*/
public String getStatus(){
return this.getAccountstate().getStatus();
}
}
抽象类 状态
package com.nj.boke.state;
import lombok.Data;
/**
* 账户状态抽象类
*/
@Data
public abstract class Accountstate {
/**
* 用户账号
*/
protected Account account;
private String status;
public Accountstate (Account account){
this.account=account;
}
protected Accountstate() {
}
/**
* 存钱方法 完整方法:
* 因为无论账户什么状态统一都可以进行存钱操作
* @param money
*/
public void cq(double money){
this.getAccount().setBalance(this.getAccount().getBalance()+money);
this.changState();
}
/**
* 取钱方法
* 根据状态不一致,取钱功能不一致
* @param money
*/
public void qq(double money){
double balance =this.getAccount().getBalance()-money;
if (balance<-this.getAccount().getAmount()){
System.out.println("您的额度不够");
return;
}
this.getAccount().setBalance(balance);
System.out.println("取钱成功");
this.changState();
System.out.println("---");
};
/**
* 改变账户状态
*/
public void changState(){
//获取账户余额
double balance = this.account.getBalance();
if ( balance >=0){
//账户正常
this.account.setAccountstate(new NormalState(this.account));
}else if(balance > -this.account.getAmount()){
//账户透支中
this.account.setAccountstate(new OverdraftState(this.account));
}else if (balance == -this.account.getAmount()){
//账户超过透支状态
this.account.setAccountstate(new RestrictedState(this.account));
}
}
}
实现类
具体几个实现,状态有 正常/透支/限制账户
/**
* 正常状态
*/
public class NormalState extends Accountstate{
public NormalState() {
}
public NormalState(Account account) {
super(account);
super.setStatus("正常");
}
}
------------------------------------------------------------
/**
* 透支状态
*/
public class OverdraftState extends Accountstate{
public OverdraftState() {
}
public OverdraftState(Account account) {
super(account);
super.setStatus("透支");
}
}
------------------------------------------------------------
/**
* 受限状态
*/
public class RestrictedState extends Accountstate{
public RestrictedState() {
}
public RestrictedState(Account account) {
super(account);
super.setStatus("受限");
}
/**
* 取钱受限
* @param money
*/
@Override
public void qq(double money) {
System.out.println("取钱功能受限");
System.out.println("---");
}
}
模拟用户操作
public static void main(String[] args) {
Accountstate state = new NormalState();
//创建一个账户
Account account=new Account(100,100,state);
state.setAccount(account);
int i=0;
while (i<6){
//用户取钱
System.out.println("==============开始取钱============");
account.qq(50);
System.out.println("用户余额"+account.getBalance());
System.out.println("用户额度"+account.getAmount());
System.out.println("用户状态"+account.getStatus());
i++;
}
while (i>0){
//用户取钱
System.out.println("==============开始存钱============");
account.cq(20);
System.out.println("用户余额"+account.getBalance());
System.out.println("用户额度"+account.getAmount());
System.out.println("用户状态"+account.getStatus());
i--;
}
}
结果如下:
==============开始取钱============
取钱成功
---
用户余额50.0
用户额度60.0
用户状态正常
==============开始取钱============
取钱成功
---
用户余额0.0
用户额度60.0
用户状态正常
==============开始取钱============
取钱成功
---
用户余额-50.0
用户额度60.0
用户状态透支
==============开始取钱============
您的额度不够
用户余额-50.0
用户额度60.0
用户状态透支
==============开始取钱============
您的额度不够
用户余额-50.0
用户额度60.0
用户状态透支
==============开始取钱============
您的额度不够
用户余额-50.0
用户额度60.0
用户状态透支
==============开始存钱============
用户余额-30.0
用户额度60.0
用户状态透支
==============开始存钱============
用户余额-10.0
用户额度60.0
用户状态透支
==============开始存钱============
用户余额10.0
用户额度60.0
用户状态正常
==============开始存钱============
用户余额30.0
用户额度60.0
用户状态正常
==============开始存钱============
用户余额50.0
用户额度60.0
用户状态正常
==============开始存钱============
用户余额70.0
用户额度60.0
用户状态正常
Process finished with exit code 0
案例来自于:微信公众号码农架构
https://mp.weixin.qq.com/s/AOQD_nmSUPwHo2PQ0dL28Q