我必须实现一个状态机,其基本要求是每个状态模式都应该具有:
stateMachine.dispenseCard()不是CASHACCEPTED,那么stateMachine.currentState()就不能工作。我试着跟踪这链接,但是这里:
发布于 2019-05-15 12:39:37
您给出的示例代码实际上定义了一个状态,它具有所有的行为或Context (本例中的Door)。 state 定义了上下文在此状态下的行为方式。
例如,当Door在DoorOpenedState中时(假设它是完全打开的)。当调用方法Open()来调用要打开的Door的行为时,应该会导致错误(无效的转换),因为您不能从DoorOpenedState转换到DoorOpenedState。
状态模式可以通过多种不同的方式来实现,状态之间的转换可以通过不同的方式来实现。如果您还没有读过高夫书,就会在这里讨论转换问题和可能的实现。
下面是一个用于供货机的状态机的示例。为了简化这个例子,并专注于状态机和转换,让我们假设我们的状态机只有面条,而且它不返回多余的钱。所以,如果一杯面条是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。
在本例中,每个状态都会进行状态转换到下一个适当的状态。
如果您有更复杂的状态机示例,您可能需要决定在哪里存储参数。您可以将其存储在上下文中(在本例中为NoodlesVendingMachine)。在这个例子中,钱被存储在一个特殊的CacheStorage中,这样每个状态和NoodlesVendingMachine都可以根据它的价值来进行决策。执行操作(例如,DispenceNoodles)时,当前状态检查CacheStorage的值,并决定是否进行转换、执行某些行为(CacheAvailableState中的TakeMoney)、抛出错误或执行行为,然后进行转换(CacheAvailableState中的ReturnCache)。
当然,如果有必要,您可以在每个State中存储临时状态特定的数据,这样它就可以根据这些数据做出决策,而不需要其他对象知道它。
在本例中,CacheAvailableState可以将AvailableCache作为属性存储在其中。我决定将它添加到另一个类中,以表明这样多个对象可以访问数据。当然,我们需要向用户显示AvailableCache,所以NoodlesVendingMachine也需要访问可用的缓存。
我们也可以将其添加到NoodlesVendingMachine中,但这将向类添加方法和属性,并增加类的大小。因此,我们使用单一责任原则并将存储缓存的责任转移到另一个类。如果我们有更多的数据,这将特别有效。
https://stackoverflow.com/questions/56147224
复制相似问题