我必须实现一个状态机,其非常基本的要求是每个状态模式都应具有:
stateMachine.dispenseCard()
不是stateMachine.currentState()
,则CASHACCEPTED
将不起作用我尝试点击this链接,但在这里:
抽象State类需要定义状态机的所有可能状态,因此具体状态需要实现所有状态方法。为什么具体的状态类对转换到其他状态的所有其他方法都感兴趣?为什么不仅要转变为这种状态?
public abstract class DoorState : DomainObject {
protected Door _door;
public Door Door
{
get { return _door; }
set { _door = value; }
}
public abstract void Close();
public abstract void Open();
public abstract void Break();
public abstract void Lock();
public abstract void Unlock();
/// <summary>
/// Fix simulates a repair to the Door and resets
/// the initial state of the door to closed.
/// </summary>
public void Fix()
{
_door.DoorState = new DoorClosedState(this);
}}
为什么State类“具有一个”转换为不同状态的Device?不应该这样吗?就像门应该“处于”状态。
答案 0 :(得分:0)
您提供的示例代码实际上定义了一个 状态 ,其中包含所有 行为 或< strong> 上下文 (在此示例中为门)。 状态 定义了在这种状态下 Context 应该如何表现。
例如,当Door
中有DoorOpenedState
时(假定它是完全打开的)。当调用方法Open()
来调用Door
的行为以打开时,则将导致错误(无效转换),因为您无法从DoorOpenedState
转换为DoorOpenedState
状态模式可以通过许多不同的方式实现,状态之间的转换可以通过不同的方式实现。如果您还没有阅读GOF book,那么他们会讨论过渡问题和可能的实现。
这是自动售货机的状态机示例。为了简化示例并专注于状态机和转换,假设我们的状态机只有面条,并且不会返还多余的钱。因此,如果一杯面条是5美元,而您给它7美元,它将不会返回2美元。
注意:由于NoodleVendingMachine
与每个状态之间都需要通信,为简单起见,我将这些方法设置为内部方法只是为了对其进行标记。对于真实的项目,可能需要附加接口才能将其从NoodleVendingMachine
的客户端代码中隐藏起来,并将它们保留在NoodleVendingMachine
和它的状态之间。
public class CacheStorage {
public Cache AvailableCache { get; private set; }
public void AddCache(Money cache) {
AvailabletCache += cache;
}
public void ClearAvailableCache() {
AvailabletCache = Money.None;
}
}
public interface INoodleVendingMachineState {
void TakeCache(Money money);
Noodles DispenceNoodles();
Money ReturnCache();
}
public class NoodleVendingMachine {
private INoodleVendingMachineState mState;
itnernal CacheStorage CacheStorage { get; private set; }
public NoodlesPrice { get; private set; }
public Money AvailableCache { get { return CacheStorage.AvailableCache; } }
public NoodleVendingMachine() {
NoodlesPrice = new Money(Currency.USD, 5); // 5 bucks for noodles
CacheStorage = new CacheStorage();
mState = new WaitingForCacheState(this);
}
public void TakeCache(Money money) {
mState.TakeCache(money);
}
public Noodles DispenceNoodles() {
return mState.DispenceNoodles();
}
public Money ReturnCache() {
return mState.ReturnCache();
}
internal void TransitionTo(INoodleVendingMachineState state) {
mState = state;
}
}
public WaitingForCacheState : INoodleVendingMachineState {
private NoodlesVendingMachine mVendingMachine;
public WaitingForCacheState(NoodlesVendingMachine vendingMachine) {
mVendingMachine = vendingMachine;
}
public void TakeCache(Money cache) {
mVendingMachine.CacheStorage.AddCache(cache);
mVendingMachine.TransitionTo(new CacheAvailableState(mVendingMachine));
}
public Noodles DispenceNoodles() {
throw new InsertCacheFirstException();
}
public Money ReturnCache() {
throw new CacheNotAvailableException();
}
}
public CacheAvailableState : INoodleVendingMachineState {
private CacheStorage mCacheStorage;
private NoodleVendingMachine mVendingMachine;
public CacheAvailableState(NoodleVendingMachine vendingMachine) {
if (vendingMachine.AvailableCache == Money.None){
throw new CacheNotAvailable()
}
mVendingMachine = vendingMachine;
mCacheStorage = mVendingMachine.CacheStorage;
}
public void TakeCache(Money cache) {
mCacheStorage.AddCache(cache);
}
public Noodles DispenceNoodles() {
if(mCacheStorage.AvailableCache < mVendingMachine.NoodlesPrice) {
throw new CacheNotEnoughtException();
}
mCacheStorage.ClearAvailableCache();
mVendingMachine.TransitionTo(new WaitingForCacheState(mVendingMachine));
return new Noodles();
}
public Money ReturnCache() {
var cache = mCacheStorage.AvailableCache;
mCacheStorage.ClearAvailableCache();
mVendingMachine.TransitionTo(new WaitingForCacheState(mVendingMachine));
return cache;
}
}
在这里,我们用状态捕获自动售货机的行为。
WaitingForCacheState
将在调用DispenceNoodles
或ReturnCache
时引发异常,因为在此状态下这是无效行为。
WaitingForCacheState
会进行到CacheAvailableState
的状态转换。当缓存可用时,我们看到支持所有行为。分发面条或用户要求退款时,我们将状态转换为WaitingForCacheState
。
在此示例中,每个状态都将状态转换为下一个适当的状态。
如果您的状态机示例更为复杂,则可能需要确定将参数存储在何处。您可以将其存储在 Context 中(在我们的情况下为NoodlesVendingMachine
)。在此示例中,货币存储在特殊的CacheStorage
中,因此每个州和NoodlesVendingMachine
都可以访问它们,并可以根据其值进行决策。当执行操作时(例如DispenceNoodles
),当前状态会检查CacheStorage
的值,并决定是否进行过渡,执行某些行为({{ 1}}),抛出错误或执行行为,然后进行转换(TakeMoney
中的CacheAvailableState
)。
当然,如有必要,您可以在每个ReturnCache
中存储临时状态特定的数据,这样它就可以基于该数据做出决策,而其他对象则不知道。
在此示例中,CacheAvailableState
可以将State
作为属性存储在其中。我决定将其添加到另一个类中,以表明通过这种方式,多个对象可以访问数据。当然,我们需要向用户显示CacheAvailableState
,因此AvailableCache
也需要访问可用的缓存。
我们也可以将其添加到AvailableCache
中,但这将为类添加方法和属性并增加其大小。因此,我们使用Single-Responsibility principle并将存储缓存的职责移到另一个类。如果我们有更多数据,这将特别有效。