State Pattern(状态模式):
允许一个对象在其内部状态改变时改变它的行为。这个对象看起来似乎修改了它的类。
能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些可能发生的外部情况全部考虑到,使用if else语句来进行代码响应选择。但是这种方法对于复杂一点的状态判断,就会显得杂乱无章,容易产生错误;而且增加一个新的状态将会带来大量的修改。这个时候“能够修改自身”的状态模式的引入也许是个不错的主意。状态模式可以有效的替换充满在程序中的if else语句:将不同条件下的行为封装在一个类里面,再给这些类一个统一的父类来约束他们。来看一下状态模式的角色组成吧:
1) 使用环境(Context)角色:客户程序是通过它来满足自己的需求。它定义了客户程序需要的接口;并且维护一个具体状态角色的实例,这个实例来决定当前的状态。
2) 状态(State)角色:定义一个接口以封装与使用环境角色的一个特定状态相关的行为。
3) 具体状态(Concrete State)角色:实现状态角色定义的接口。
类图如下,结构非常简单也与策略模式非常相似。
什么时候该使用状态模式:
1) 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
2) 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
/**
*维护一个ConcreteState子类的一个实例,这个实例定义当前的状态
*/
public class Context {
private State state;
public void setState(State state) {
this.state = state;
System.out.println("当前状态是:" + state.GetType().Name);
}
public State getState() {
return state;
}
public Context(State state) {
this.state = state;
System.out.println("初始状态是:"+state.GetType().Name);
}
public void Request() {
state.Handle(this);
}
}
/**
*抽象状态类及其具体实现类
*/
public abstract class State {
public abstract void Handle(Context context);
}
public class ConcreteStateA extends State {
@override
public void Handle(Context context){
context.State = new ConcreteStateB();
}
}
public class ConcreteStateB extends State {
@override
public void Handle(Context context) {
context.State = new ConcreteStateC();
}
}
public class ConcreteStateC extends State {
@override
public void Handle(Context context) {
context.State = new ConcreteStateA();
}
}
/**
*客户端代码
*/
static void Main(string[] args){
Context context = new Context(new ConcreteStateA());
context.Request();
context.Request();
context.Request();
Console.Read();
}
案例分析:
场景
银行账户根据余额可分为三种状态RedState,SilverState,GoldState,这些状态分别代表了透支帐户(overdrawn accounts),新开帐户(starter accounts),标准帐户(accounts in good standing)..如下图所示
RedState类:账号余额在范围【0.0,1000.0】表示处于处于SilverState。否则转换为其他状态。
if (balance < lowerLimit)
{
account.State = new RedState(this);
}
else if (balance > upperLimit)
{
account.State = new GoldState(this);
}
SilverState类:账号余额在范围【-100.0,0】表示处于处于RedState。否则转换为其他状态。
if (balance > upperLimit)
{
account.State = new SilverState(this);
}
GoldState类:账号余额在范围【1000.0,10000000.0】表示处于处于GoldState。否则转换为其他状态。
if (balance < 0.0)
{
account.State = new RedState(this);
}
else if (balance < lowerLimit)
{
account.State = new SilverState(this);
}
/**
*类Account,相当于Context类
*/
public class Account {
private State _state;
private string _owner;
public Account(string owner) {
this._owner = owner;
this._state = new SilverState(0.0, this);
}
public double getBalance {
return _state.Balance;
}
public State setState(State state) {
this._state = state;
}
public void getState() {
return _state;
}
public void Deposit(double amount) {
_state.Deposit(amount);
System.out.println("Deposited {0:C} --- ", amount);
System.out.println("Balance = {0:C}", this.Balance);
System.out.println("Status = {0}",
this._state.GetType().Name;
}
public void Withdraw(double amount) {
_state.Withdraw(amount);
System.out.println("Withdrew {0:C} --- ", amount);
System.out.println(" Balance = {0:C}", this.Balance);
System.out.println(" Status = {0}\n",
this._state.GetType().Name;
}
public void PayInterest() {
_state.PayInterest();
System.out.println("Interest Paid --- ");
System.out.println(" Balance = {0:C}", this.Balance);
System.out.println(" Status = {0}\n",
this.State.GetType().Name;
}
}
/**
*抽象状态类State及其具体状态类RedState,SilverState,GoldState
*/
public abstract class State {
protected Account account;
protected double balance;
protected double interest;
protected double lowerLimit;
protected double upperLimit;
public void setAccount(Account account) {
this.account = account;
}
public Account getAccount() {
return this.account;
}
public void setBalance(doublie balance) {
this.balance = balance;
}
public double getBalance() {
return this.balance;
}
public abstract void Deposit(double amount);
public abstract void Withdraw(double amount);
public abstract void PayInterest();
}
public class RedState extends State {
private double _serviceFee;
public RedState(State state) {
this.balance = state.Balance;
this.account = state.Account;
Initialize();
}
private void Initialize() {
interest = 0.0;
lowerLimit = -100.0;
upperLimit = 0.0;
_serviceFee = 15.00;
}
public override void Deposit(double amount) {
balance += amount;
StateChangeCheck();
}
@override
public void Withdraw(double amount) {
amount = amount - _serviceFee;
System.out.println("No funds available for withdrawal!");
}
@override
public void PayInterest() { // No interest is paid }
private void StateChangeCheck() {
if(balance > upperLimit) {
account.State = new SilverState(this);
}
}
}
public class SilverState extends State {
public SilverState(State state) {
super(state.Balance, state.Account);
}
public SilverState(double balance, Account account) {
this.balance = balance;
this.account = account;
Initialize();
}
private void Initialize() {
interest = 0.0;
lowerLimit = 0.0;
upperLimit = 1000.0;
}
@override
public void Deposit(double amount) {
balance += amount;
StateChangeCheck();
}
@override
public override void Withdraw(double amount) {
balance -= amount;
StateChangeCheck();
}
@override
public void PayInterest() {
balance += interest * balance;
StateChangeCheck();
}
private void StateChangeCheck() {
if (balance < lowerLimit) {
account.State = new RedState(this);
} else if (balance > upperLimit) {
account.State = new GoldState(this);
}
}
}
public class GoldState extends State{
public GoldState(State state) {
super(state.Balance, state.Account);
}
public GoldState(double balance, Account account){
this.balance = balance;
this.account = account;
Initialize();
}
private void Initialize() {
interest = 0.05;
lowerLimit = 1000.0;
upperLimit = 10000000.0;
}
public override void Deposit(double amount) {
balance += amount;
StateChangeCheck();
}
@override
public void Withdraw(double amount) {
balance -= amount;
StateChangeCheck();
}
@override
public void PayInterest() {
balance += interest * balance;
StateChangeCheck();
}
private void StateChangeCheck() {
if (balance < 0.0) {
account.State = new RedState(this);
} else if (balance < lowerLimit) {
account.State = new SilverState(this);
}
}
}
public static void Main(string[] args) {
Account account = new Account("Jim Johnson");
account.Deposit(500.0);
account.Deposit(300.0);
account.Deposit(550.0);
account.PayInterest();
account.Withdraw(2000.00);
account.Withdraw(1100.00);
}
dai ma mei you ce shi , jin wei shuo ming ye wu luo ji
状态VS策略
仔细对比状态模式和策略模式,难免会产生疑问:这两个明明是一个东西嘛!下面我们就来分析下两者区别。
首先我要声明,在实际应用中只要能够使得你的代码灵活漂亮起来,何必计较这些方方面面的差别呢?
BrandonGoldfedder在《模式的乐趣》里是怎么说的:“strategy模式在结构上与state模式非常相似,但是在概念上,他们的目的差异非常大。区分这两个模式的关键是看行为是由状态驱动还是由一组算法驱动,这条规则似乎有点随意,但是在判断时还是需要考虑它。通常,State模式的“状态”是在对象内部的,Strategy模式的“策略”可以在对象外部,不过这也不是一条严格、可靠的规则。”
我很同意Brandon Goldfedder的观点。这两个模式的划分,就在于使用的目的是不同的——策略模式用来处理算法变化,而状态模式则是处理状态变化(好玄乎阿)。
策略模式中,算法是否变化完全是由客户程序开决定的,而且往往一次只能选择一种算法,不存在算法中途发生变化的情况。从《深入浅出策略模式》中的例子可以很好的看出。
而状态模式如定义中所言,在它的生命周期中存在着状态的转变和行为得更改,而且状态变化是一个线形的整体;对于客户程序来言,这种状态变化往往是透明的。