设计模式(19)状态模式
模式介绍
状态模式旨在允许对象在其内部状态改变时改变其自身行为。
示例
我们以烤牛排为例,生熟程度分为:
- Uncooked (not safe to eat)
- Rare
- Medium-Rare (mid-rare)
- Medium
- Medium-Well (mid-well)
- Well done
简单来说就是从生到熟的几个档次。
抽象的状态类:
/// <summary>
/// The State abstract class
/// </summary>
abstract class Doneness
{
protected Steak steak;
protected double currentTemp;
protected double lowerTemp;
protected double upperTemp;
protected bool canEat;
public Steak Steak
{
get { return steak; }
set { steak = value; }
}
public double CurrentTemp
{
get { return currentTemp; }
set { currentTemp = value; }
}
public abstract void AddTemp(double temp);
public abstract void RemoveTemp(double temp);
public abstract void DonenessCheck();
}
具体的状态类:
/// <summary>
/// A Concrete State class.
/// </summary>
class Uncooked : Doneness
{
public Uncooked(Doneness state)
{
currentTemp = state.CurrentTemp;
steak = state.Steak;
Initialize();
}
private void Initialize()
{
lowerTemp = 0;
upperTemp = 130;
canEat = false;
}
public override void AddTemp(double amount)
{
currentTemp += amount;
DonenessCheck();
}
public override void RemoveTemp(double amount)
{
currentTemp -= amount;
DonenessCheck();
}
public override void DonenessCheck()
{
if (currentTemp > upperTemp)
{
steak.State = new Rare(this);
}
}
}
/// <summary>
/// A 'ConcreteState' class.
/// </summary>
class Rare : Doneness
{
public Rare(Doneness state) : this(state.CurrentTemp, state.Steak)
{
}
public Rare(double currentTemp, Steak steak)
{
this.currentTemp = currentTemp;
this.steak = steak;
canEat = true; //We can now eat the steak
Initialize();
}
private void Initialize()
{
lowerTemp = 130;
upperTemp = 139.999999999999;
canEat = true;
}
public override void AddTemp(double amount)
{
currentTemp += amount;
DonenessCheck();
}
public override void RemoveTemp(double amount)
{
currentTemp -= amount;
DonenessCheck();
}
public override void DonenessCheck()
{
if (currentTemp < lowerTemp)
{
steak.State = new Uncooked(this);
}
else if (currentTemp > upperTemp)
{
steak.State = new MediumRare(this);
}
}
}
/// <summary>
/// A Concrete State class
/// </summary>
class MediumRare : Doneness
{
public MediumRare(Doneness state) : this(state.CurrentTemp, state.Steak)
{
}
public MediumRare(double currentTemp, Steak steak)
{
this.currentTemp = currentTemp;
this.steak = steak;
canEat = true;
Initialize();
}
private void Initialize()
{
lowerTemp = 140;
upperTemp = 154.9999999999;
}
public override void AddTemp(double amount)
{
currentTemp += amount;
DonenessCheck();
}
public override void RemoveTemp(double amount)
{
currentTemp -= amount;
DonenessCheck();
}
public override void DonenessCheck()
{
if (currentTemp < 0.0)
{
steak.State = new Uncooked(this);
}
else if (currentTemp < lowerTemp)
{
steak.State = new Rare(this);
}
else if (currentTemp > upperTemp)
{
steak.State = new Medium(this);
}
}
}
/// <summary>
/// A Concrete State class
/// </summary>
class Medium : Doneness
{
public Medium(Doneness state) : this(state.CurrentTemp, state.Steak)
{
}
public Medium(double currentTemp, Steak steak)
{
this.currentTemp = currentTemp;
this.steak = steak;
canEat = true;
Initialize();
}
private void Initialize()
{
lowerTemp = 155;
upperTemp = 169.9999999999;
}
public override void AddTemp(double amount)
{
currentTemp += amount;
DonenessCheck();
}
public override void RemoveTemp(double amount)
{
currentTemp -= amount;
DonenessCheck();
}
public override void DonenessCheck()
{
if (currentTemp < 130)
{
steak.State = new Uncooked(this);
}
else if (currentTemp < lowerTemp)
{
steak.State = new MediumRare(this);
}
else if (currentTemp > upperTemp)
{
steak.State = new WellDone(this);
}
}
}
/// <summary>
/// A Concrete State class
/// </summary>
class WellDone : Doneness //aka Ruined
{
public WellDone(Doneness state) : this(state.CurrentTemp, state.Steak)
{
}
public WellDone(double currentTemp, Steak steak)
{
this.currentTemp = currentTemp;
this.steak = steak;
canEat = true;
Initialize();
}
private void Initialize()
{
lowerTemp = 170;
upperTemp = 230;
}
public override void AddTemp(double amount)
{
currentTemp += amount;
DonenessCheck();
}
public override void RemoveTemp(double amount)
{
currentTemp -= amount;
DonenessCheck();
}
public override void DonenessCheck()
{
if (currentTemp < 0)
{
steak.State = new Uncooked(this);
}
else if (currentTemp < lowerTemp)
{
steak.State = new Medium(this);
}
}
}
上下文类-牛排:
/// <summary>
/// The Context class
/// </summary>
class Steak
{
private Doneness _state;
private string _beefCut;
public Steak(string beefCut)
{
_cook = beefCut;
_state = new Rare(0.0, this);
}
public double CurrentTemp
{
get { return _state.CurrentTemp; }
}
public Doneness State
{
get { return _state; }
set { _state = value; }
}
public void AddTemp(double amount)
{
_state.AddTemp(amount);
Console.WriteLine("Increased temperature by {0} degrees.", amount);
Console.WriteLine(" Current temp is {0}", CurrentTemp);
Console.WriteLine(" Status is {0}", State.GetType().Name);
Console.WriteLine("");
}
public void RemoveTemp(double amount)
{
_state.RemoveTemp(amount);
Console.WriteLine("Decreased temperature by {0} degrees.", amount);
Console.WriteLine(" Current temp is {0}", CurrentTemp);
Console.WriteLine(" Status is {0}", State.GetType().Name);
Console.WriteLine("");
}
}
客户端调用:
static void Main(string[] args)
{
//Let's cook a steak!
Steak account = new Steak("T-Bone");
// Apply temperature changes
account.AddTemp(120);
account.AddTemp(15);
account.AddTemp(15);
account.RemoveTemp(10); //Yes I know cooking doesn't work this way, bear with me.
account.RemoveTemp(15);
account.AddTemp(20);
account.AddTemp(20);
account.AddTemp(20);
Console.ReadKey();
}
总结
状态模式允许对象的行为随着其内部状态的改变而改变,并且它通过使对象的状态与对象本身分开来完成这一任务。
因此,状态可以为对象实现它们自己的行为,并且对象可以对其内部状态改变作出“反应”。
源代码
https://github.com/exceptionnotfound/DesignPatterns/tree/master/State
原文
https://www.exceptionnotfound.net/state-the-daily-design-pattern/