首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >国家模式的实施

问国家模式的实施
EN

Stack Overflow用户
提问于 2019-05-15 10:32:40
回答 1查看 145关注 0票数 0

我必须实现一个状态机,其基本要求是每个状态模式都应该具有:

  1. 状态机一次可以处于任意一个状态。
  2. 从X态到Y态的转变将比从Y状态到Z状态或从任何其他状态到另一个状态的转变具有不同的参数。
  3. 用户程序,它将操作“状态机”,当然,不能转换到一个状态,如果你在一个特定的状态是不允许的。例如,如果stateMachine.dispenseCard()不是CASHACCEPTED,那么stateMachine.currentState()就不能工作。

我试着跟踪这链接,但是这里:

  1. 抽象的状态类需要定义状态机的所有可能状态,因此具体的状态需要实现所有的状态方法。为什么具体的国家阶级应该对所有其他的方法感兴趣,这些方法会转移到其他国家呢?为什么不只是国家转嫁的那些人呢? 公共抽象类DoorState : DomainObject {受保护的门_door;公共门{ get {返回_door;} set { _door = value;}公共抽象虚空关闭();公共抽象空洞打开();公共抽象空洞断开();公共抽象虚锁();公共抽象虚锁(解锁);/ Fix模拟对门进行修复并重置/门的初始关闭状态。/ public void (){ _door.DoorState =新的DoorClosedState(this);}}
  2. 为什么国家阶级“有一个”的装置,可以转换到不同的状态?不应该是相反的吗?就像门应该有“有”的状态。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-05-15 12:39:37

您给出的示例代码实际上定义了一个状态,它具有所有的行为或Context (本例中的Door)。 state 定义了上下文在此状态下的行为方式。

例如,当Door在DoorOpenedState中时(假设它是完全打开的)。当调用方法Open()来调用要打开的Door的行为时,应该会导致错误(无效的转换),因为您不能从DoorOpenedState转换到DoorOpenedState。

状态模式可以通过多种不同的方式来实现,状态之间的转换可以通过不同的方式来实现。如果您还没有读过高夫书,就会在这里讨论转换问题和可能的实现。

下面是一个用于供货机的状态机的示例。为了简化这个例子,并专注于状态机和转换,让我们假设我们的状态机只有面条,而且它不返回多余的钱。所以,如果一杯面条是5美元,你给它7美元,它就不会返回2美元。

注意:由于为了简单起见,需要NoodleVendingMachine和每个状态之间的通信,所以我将使这些方法在内部进行标记。对于一个实际的项目,可能需要一个附加接口,以便将它们隐藏在NoodleVendingMachine的客户端代码中,并将它们保持在NoodleVendingMachine和它的状态之间。

代码语言:javascript
复制
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中,但这将向类添加方法和属性,并增加类的大小。因此,我们使用单一责任原则并将存储缓存的责任转移到另一个类。如果我们有更多的数据,这将特别有效。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56147224

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档