设计模式之状态模式(上)

状态模式
1)概述
1.定义

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

2.作用

状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

3.方案

状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,客户端都可以一致处理。

4.结构图
5.角色

Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象,在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。

State(抽象状态类) :定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中

ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。

6.代码实现

抽象状态类

abstract class State {
  //声明抽象业务方法,不同的具体状态类可以不同的实现
	public abstract void handle();
}

具体状态类

public class ConcreteState extends State {
	public void handle() {
		//方法具体实现代码
	}
}

环境类

public class Context {
  //维持一个对抽象状态对象的引用
	private State state; 
	//其他属性值,该属性值的变化可能会导致对象状态发生变化
	private int value; 
 
    //设置状态对象
	public void setState(State state) {
		this.state = state;
	}
 
	public void request() {
		//调用状态对象的业务方法
		state.handle(); 
	}
}

在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换,通常有两种实现状态转换的方式。

统一由环境类来负责状态之间的转换:环境类充当了状态管理器(State Manager)角色,在环境类的业务方法中通过对某些属性值的判断实现状态转换,还可以提供一个专门的方法用于实现属性判断和状态转换。

	......
  public void changeState() {
		  //判断属性值,根据属性值进行状态转换
      if (value == 0){
			  this.setState(new ConcreteStateA());
		  }else if (value == 1){
			  this.setState(new ConcreteStateB());
		  }
	}
  ......

由具体状态类负责状态之间的转换:在具体状态类的业务方法中判断环境类的某些属性值再根据情况为环境类设置新的状态对象,实现状态转换,也可以提供一个专门的方法来负责属性值的判断和状态转换,此时,状态类与环境类之间存在依赖或关联关系,因为状态类需要访问环境类中的属性值。

	......
  public void changeState(Context ctx) {
		//根据环境对象中的属性值进行状态转换
    if (ctx.getValue() == 1){
			ctx.setState(new ConcreteStateB());
		}else if (ctx.getValue() == 2){
			ctx.setState(new ConcreteStateC());
		}
  }
  ......
2)完整解决方案
1.结构图

Account充当环境类角色,AccountState充当抽象状态角色,NormalState、OverdraftState和RestrictedState充当具体状态角色。

2.代码实现
//银行账户:环境类
public class Account {
  //维持一个对抽象状态对象的引用
	private AccountState state; 
	//开户名
	private String owner; 
	//账户余额
	private double balance = 0; 
	
	public Account(String owner,double init) {
		this.owner = owner;
		this.balance = balance;
		//设置初始状态
		this.state = new NormalState(this); 
		System.out.println(this.owner + "开户,初始金额为" + init);	
		System.out.println("---------------------------------------------");	
	}
	
	public double getBalance() {
		return this.balance;
	}
	
	public void setBalance(double balance) {
		this.balance = balance;
	}
	
	public void setState(AccountState state) {
		this.state = state;
	}
	
	public void deposit(double amount) {
		System.out.println(this.owner + "存款" + amount);
		//调用状态对象的deposit()方法
		state.deposit(amount); 
		System.out.println("现在余额为"+ this.balance);
		System.out.println("现在帐户状态为"+ this.state.getClass().getName());
		System.out.println("---------------------------------------------");			
	}
	
	public void withdraw(double amount) {
		System.out.println(this.owner + "取款" + amount);
		//调用状态对象的withdraw()方法
    state.withdraw(amount); 
		System.out.println("现在余额为"+ this.balance);
		System.out.println("现在帐户状态为"+ this. state.getClass().getName());		
		System.out.println("---------------------------------------------");
	}
	
	public void computeInterest()
	{ 
	  //调用状态对象的computeInterest()方法
		state.computeInterest(); 
	}
}
 
//抽象状态类
abstract class AccountState {
	protected Account acc;
	public abstract void deposit(double amount);
	public abstract void withdraw(double amount);
	public abstract void computeInterest();
	public abstract void stateCheck();
}
 
//正常状态:具体状态类
public class NormalState extends AccountState {
	public NormalState(Account acc) {
		this.acc = acc;
	}
 
  public NormalState(AccountState state) {
		this.acc = state.acc;
	}
		
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		acc.setBalance(acc.getBalance() - amount);
		stateCheck();
	}
	
	public void computeInterest()
	{
		System.out.println("正常状态,无须支付利息!");
	}
	
    //状态转换
	public void stateCheck() {
		if (acc.getBalance() > -2000 && acc.getBalance() <= 0) {
			acc.setState(new OverdraftState(this));
		}
		else if (acc.getBalance() == -2000) {
			acc.setState(new RestrictedState(this));
		}
		else if (acc.getBalance() < -2000) {
			System.out.println("操作受限!");
		}	
	}   
}  
 
//透支状态:具体状态类
public class OverdraftState extends AccountState
{
	public OverdraftState(AccountState state) {
		this.acc = state.acc;
	}
	
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		acc.setBalance(acc.getBalance() - amount);
		stateCheck();
	}
	
	public void computeInterest() {
		System.out.println("计算利息!");
	}
	
  //状态转换
	public void stateCheck() {
		if (acc.getBalance() > 0) {
			acc.setState(new NormalState(this));
		}
		else if (acc.getBalance() == -2000) {
			acc.setState(new RestrictedState(this));
		}
		else if (acc.getBalance() < -2000) {
			System.out.println("操作受限!");
		}
	}
}
 
//受限状态:具体状态类
public class RestrictedState extends AccountState {
	public RestrictedState(AccountState state) {
		this.acc = state.acc;
	}
	
	public void deposit(double amount) {
		acc.setBalance(acc.getBalance() + amount);
		stateCheck();
	}
	
	public void withdraw(double amount) {
		System.out.println("帐号受限,取款失败");
	}
	
	public void computeInterest() {
		System.out.println("计算利息!");
	}
	
    //状态转换
	public void stateCheck() {
		if(acc.getBalance() > 0) {
			acc.setState(new NormalState(this));
		}
		else if(acc.getBalance() > -2000) {
			acc.setState(new OverdraftState(this));
		}
	}
}

客户端测试类

public class Client {
	public static void main(String args[]) {
		Account acc = new Account("段誉",0.0);
		acc.deposit(1000);
		acc.withdraw(2000);
		acc.deposit(3000);
		acc.withdraw(4000);
		acc.withdraw(1000);
		acc.computeInterest();
	}
}
相关推荐
Crossoads1 小时前
【汇编语言】端口 —— 「从端口到时间:一文了解CMOS RAM与汇编指令的交汇」
android·java·汇编·深度学习·网络协议·机器学习·汇编语言
老马啸西风1 小时前
NLP 中文拼写检测纠正论文-02-2019-SOTA FASPell Chinese Spell Checke github 源码介绍
java
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
@菜鸟进阶记@1 小时前
java根据Word模板实现动态填充导出
java·开发语言
卖芒果的潇洒农民1 小时前
Lecture 6 Isolation & System Call Entry
java·开发语言
Amarantine、沐风倩✨2 小时前
设计一个监控摄像头物联网IOT(webRTC、音视频、文件存储)
java·物联网·音视频·webrtc·html5·视频编解码·七牛云存储
路在脚下@3 小时前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
森屿Serien3 小时前
Spring Boot常用注解
java·spring boot·后端
Damon_X3 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
苹果醋34 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx