上一篇:设计模式(十七)——备忘录模式
下一篇:设计模式(十九)——策略模式
一、概述
官方解释:Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(当一个对象在状态改变时允许其改变行为,这个对象看起来像改变了其类。)
我的理解:
设计的时候,将State引用注入到Context类中,状态设置判断一般用boolean或int;
运行的时候,客户端通过调用Context类对象的方法,间接操作State类,即完成了状态变化,又很好的在客户端隐藏了State类。
参与者:Context环境类、State状态类(抽象状态类、具体状态类)
类图:
二、代码
代码1——开门关门实例(boolean类型变量为状态判断) 代码2——银行存款取款实例(int类型变量为状态判断)
代码1——开门关门实例(boolean类型变量为状态判断):
package mypackage;
public class DesignPatternDemo {
public static void main(String[] args) {
Door door=new Door(true);
door.request();
door.request();
door.request();
}
}
abstract class State{
protected Door door;
public abstract void handle();
public abstract void stateCheck();
}
class OpenState extends State{
@Override
public void handle() {
//具体操作 handle方法
door.isOpen=!door.isOpen;
stateCheck();
}
public OpenState(State state) {
this.door=state.door;
}
public OpenState(Door door) {
this.door=door;
}
@Override
public String toString() {
return "OpenState";
}
@Override
public void stateCheck() {
//状态更新
if (door.isOpen) {
door.setState(new OpenState(this));
}else {
door.setState(new CloseState(this));
}
}
}
class CloseState extends State{
@Override
public void handle() {
//具体操作 handle方法
door.isOpen=!door.isOpen;
stateCheck();
}
public CloseState(Door door) {
this.door=door;
}
public CloseState(State state) {
this.door=state.door;
}
@Override
public String toString() {
return "CloseState";
}
@Override
public void stateCheck() {
//状态更新
if (door.isOpen) {
door.setState(new OpenState(this));
}else {
door.setState(new CloseState(this));
}
}
}
class Door{
private State state; //state引用注入环境类Context
public boolean isOpen; //通过判断value的变化来改变状态 一般是int或boolean类型
public void setState(State state){
this.state=state;
}
public State getState(){
return this.state;
}
public void request(){
state.handle();//调用state类方法
System.out.println(state);
}
public Door(boolean isOpen){
this.isOpen=isOpen;
if (isOpen) {
state=new OpenState(this);
}else {
state=new CloseState(this);
}
}
}
输出1:
CloseState
OpenState
CloseState
代码2——银行存款取款实例(int类型变量为状态判断):
package mypackage;
public class DesignPatternDemo {
public static void main(String[] args) {
Account account=new Account("张三",0.0); //新建环境类 Account 银行账户
account.deposit(1000); //将state注入到Account类中 通过操作Account间接操作state
account.withdraw(2000);
account.deposit(3000);
account.withdraw(4000);
account.withdraw(1000);
}
}
class Account { // 账户类 就是环境类Context
private AccountState state; // 注入state 就要调用state的方法 deposit withdraw
// computeInterest checkState
private String owner;
private double balance = 0;// 余额
public Account(String owner,double balance){
this.owner=owner;
this.balance=balance;
this.state=new NormalState(this); //初试为正常状态
System.out.println(owner+" 开户,初始金额为: "+balance);
System.out.println("===========================");
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getBalance() {
return this.balance;
}
public void setState(AccountState state) {
this.state = state;
}
public void deposit(double amount) {
System.out.println(this.owner + " 存款 " + amount);
state.deposit(amount);
System.out.println("当前余额: " + this.balance + " ,当前状态: " + this.state);
System.out.println("===========================");
}
public void withdraw(double amount) {
System.out.println(this.owner + " 取款 " + amount);
state.withdraw(amount);
System.out.println("当前余额: " + this.balance + " ,当前状态: " + this.state);
System.out.println("===========================");
}
}
abstract class AccountState { // 账户状态父类
protected Account account;
public abstract void deposit(double amount);// 存款
public abstract void withdraw(double amount);// 取款
public abstract void stateCheck(); //账户状态检测和设置入口 一般通过boolean或数字int判断来设置状态 这里用int
//每次操作后要跟新状态变化
}
// 正常状态
class NormalState extends AccountState {
public NormalState(Account account) { // 构造函数 形参为Account
this.account = account;
}
public NormalState(AccountState state) { // 构造函数 形参为State
this.account = state.account;
}
public void deposit(double amount) {
account.setBalance(account.getBalance() + amount);
stateCheck();//每一次存款、取款操作完成后 根据余额更新状态
}
public void withdraw(double amount) {
account.setBalance(account.getBalance() - amount);
stateCheck();//每一次存款、取款操作完成后 根据余额更新状态
}
public void computeInterest() {
System.out.println("正常状态,无需利息");
}
public void stateCheck() { // 状态改变 每一次存款、取款操作完成后 根据余额更新状态
if (account.getBalance() > -2000 && account.getBalance() <= 0) {
account.setState(new OverdraftState(this));
} else if (account.getBalance() == -2000) {
account.setState(new RestrictedState(this));
} else if (account.getBalance() < -2000) {
System.out.println("操作受限");
}
}
@Override
public String toString() {
return "正常状态";
}
}
// 透支状态
class OverdraftState extends AccountState {
public OverdraftState(AccountState state) {
this.account = state.account;
}
@Override
public void deposit(double amount) {
account.setBalance(account.getBalance() + amount);
stateCheck();//每一次存款、取款操作完成后 根据余额更新状态
}
@Override
public void withdraw(double amount) {
account.setBalance(account.getBalance() - amount);
stateCheck();//每一次存款、取款操作完成后 根据余额更新状态
}
@Override
public void stateCheck() {
if (account.getBalance() > -2000 && account.getBalance() <= 0) {
account.setState(new OverdraftState(this));
} else if (account.getBalance() == -2000) {
account.setState(new RestrictedState(this));
} else if (account.getBalance() < -2000) {
System.out.println("操作受限");
}
}
@Override
public String toString() {
return "透支状态";
}
}
// 受限状态
class RestrictedState extends AccountState {
public RestrictedState(AccountState state) {
this.account = account;
}
@Override
public void deposit(double amount) {
account.setBalance(account.getBalance() + amount);
stateCheck();//每一次存款、取款操作完成后 根据余额更新状态
}
@Override
public void withdraw(double amount) {
System.out.println("操作受限,取款失败");//受限状态下无法取款
}
@Override
public void stateCheck() {
if (account.getBalance() > 0) {
account.setState(new NormalState(this));
} else if (account.getBalance() > -2000) {
account.setState(new OverdraftState(this));
}
}
@Override
public String toString() {
return "受限状态";
}
}
输出2:
张三 开户,初始金额为: 0.0
===========================
张三 存款 1000.0
当前余额: 1000.0 ,当前状态: 正常状态
===========================
张三 取款 2000.0
当前余额: -1000.0 ,当前状态: 透支状态
===========================
张三 存款 3000.0
当前余额: 2000.0 ,当前状态: 透支状态
===========================
张三 取款 4000.0
当前余额: -2000.0 ,当前状态: 受限状态
===========================
张三 取款 1000.0
操作受限,取款失败
当前余额: -2000.0 ,当前状态: 受限状态
===========================
三、小结
状态模式:状态State是环境类Context的一个属性,代码1中Door类有Open和Close两种状态,代码2中Account类有正常状态、透支状态、受限状态三种状态,因为状态是环境类的一个属性,所有把State引用注入到Context类中,这是状态模式的关键。
State引用注入到Context类后,客户端就可以通过操作Context类对象来间接操作State类对象,很好的向客户端屏蔽了State类。
注意:至于Context引用是否需要注入到State类中,无关紧要,不是必须,本文两段代码为了操作方便,所有将Context引用注入到了State类中。
设计模式只重其意不重其形,学习每一中设计模式的时候,只要抓住它的最关键的点就好了,没有必要死记代码,代码为业务需求服务,设计模式也是如此。
附:状态模式与策略模式区别
1、类图、类的结构一样:
状态模式:Context环境类、State类(抽象状态类、具体状态类)
策略模式:Context环境类、Strategy类(抽象策略类、具体策略类)
两种模式都是行为型模式,UML图相同,都是将核心类(State类或Strategy类)注入到Context类中,在客户端通过操作Context环境类间接操作核心类(State类或Strategy类),巧妙的在客户端屏蔽核心类。
2、表达意义稍有不同:
状态可以看作是Context类的一个内在属性,是必不可少的,新建Context类对象时,Context类的初始化函数中就要初始化状态属性;
策略不是Context的属性,是Context类调用的一个外界的东西;
所以,一般核心类(State类或Strategy类)是内在属性的时候是状态模式,是外界东西的时候是策略模式。
3、代码逻辑稍有不同:状态模式是含有“状态切换”逻辑(最大的不同)
状态模式中一定含有“状态切换”逻辑,不管是在ConcreteState类中还是在Context类中,状态类中一定含有“状态切换”代码;
策略模式只是简单的在客户端切换策略,核心类(Strategy类)中没有“切换”逻辑。
其实,正是因为第二条,State是Context内在属性,所以有切换逻辑,Strategy是外在东西,所有没有切换逻辑。
所以,存在核心类(State类或Strategy类)切换逻辑的是状态模式,不存在的是策略模式。
状态模式:
https://blog.csdn.net/qq_36963950/article/details/102866284
策略模式:
https://blog.csdn.net/qq_36963950/article/details/102866291
上一篇:设计模式(十七)——备忘录模式
下一篇:设计模式(十九)——策略模式