两个不同价值观的原因是什么?

时间:2013-12-02 19:45:19

标签: java state transition state-machine

我正在尝试创建一个自治状态机。下面几乎是我的代码。它的作用是将状态转换为ROBBINGBANK,然后检查值的变化以及是否需要更改状态。在每个州,它都会增加价值或减少价值。但是当我测试它时,它不会给出错误。但它制作了财富价值的副本;我的意思是,changeState中的值与robberStats中的值不同。这就是为什么它总是处于同一状态。现在我知道问题但不是解决方案。有人可以帮忙吗?

State st = State.ROBBINGBANK;
    public enum State {

        ROBBINGBANK,
        HAVINGGOODTIME,
        FLEEING,
        LAYINGLOW,
        CAUGHT
    }

    public void changeState() throws InterruptedException {
        BankRobber br = new BankRobber();
        while (st != State.CAUGHT) {
            if (st == State.ROBBINGBANK) {
                // got rich
                if (wealth >= 5000 && strength > 0) {
                    st = State.HAVINGGOODTIME;
                } // got tired
                else if (strength <= 0) {
                    st = State.LAYINGLOW;
                } // spotted cop
                else if (distanceToCop <= 20 && strength > 0) {
                    st = State.FLEEING;
                }
            } else if (st == State.HAVINGGOODTIME) {
                // got poor
                if (wealth <= 500 && strength > 0) {
                    st = State.ROBBINGBANK;
                } // spotted cop
                else if (distanceToCop <= 20 && strength > 0) {
                    st = State.FLEEING;
                } // got tired
                else if (strength <= 0) {
                    st = State.LAYINGLOW;
                }
            } else if (st == State.FLEEING) {
                // feel safe
                if (distanceToCop >= 50 && strength > 0) {
                    st = State.ROBBINGBANK;
                } // got tired
                if (strength <= 0) {
                    st = State.LAYINGLOW;
                }
            } else if (st == State.LAYINGLOW) {
                // feel safe
                if (distanceToCop >= 50 && strength > 0) {
                    st = State.ROBBINGBANK;
                }
            }
            else if(distanceToCop <= 0){
                st = State.CAUGHT;
            }
            br.robberStats();
            Thread.sleep(2000);
        }
    }

    public void robberStats() {
        if (st == State.ROBBINGBANK) {
            if (distanceToCop >= 20 && strength >= 8) {
                distanceToCop -= 20;
                strength -= 8;
            } else if (distanceToCop >= 20) {
                distanceToCop -= 20;
            } else if (strength >= 8) {
                strength -= 8;
            }
            wealth += 1000;
        } else if (st == State.HAVINGGOODTIME) {
            if (distanceToCop >= 10 && strength >= 2) {
                distanceToCop -= 10;
                strength -= 2;
            } else if (distanceToCop >= 10) {
                distanceToCop -= 10;
            } else if (strength >= 2) {
                strength -= 2;
            }
            wealth -= 150;
        } else if (st == State.FLEEING) {
            if (strength >= 4) {
                strength -= 4;
            }
            wealth -= 100;
            distanceToCop += 10;
        } else if (st == State.LAYINGLOW) {
            strength += 10;
        }

        System.out.println("wealth: " + wealth);
        System.out.println("strength: " + strength);
        System.out.println("distanceToCop: " + distanceToCop + "\n");
    }

1 个答案:

答案 0 :(得分:1)

这不能回答你的主要问题,但你说你赞赏建设性的批评...... :)

我建议你为每个状态使用State Pattern和一个对象,而不是一个改变状态的对象。这会将你的逻辑划分为更容易阅读的一口大小的片段。

我建议不要使用状态枚举,因为它会使您更难以在以后可靠地更改/添加状态并使代码不那么灵活。但是,如果为状态转换定义接口,则可以使State实现该接口,然后将逻辑移动到State enum。那没关系,因为你可以保持开放状态来添加界面的新实现而不必强制将它们添加到枚举中。

我还建议您在编写使其通过的代码之前逐个编写自动化测试。这样,您就无法达到代码不起作用的程度。它将在每一步都有效,如果您进行设计更改,测试将保护您。


更新:

@TheTerribleSwiftTomato

使用枚举并不排除划分状态转换逻辑。恰恰相反。它可以为该逻辑提供合理的位置,即将依赖于状态的逻辑放在状态对象本身(状态模式)中。枚举的问题是它们往往会违反open/closed principle

在许多情况下,没关系;状态集非常稳定和/或可以轻松添加额外的枚举。在OP的情况下,状态(ROBBING_BANK,FLEEING,LAYING_LOW等)在我看来很可能会改变(例如INTERROGATED,ON_BAIL,FACING_JURY,SKIPPING_BAIL)。通过使用界面,我们可以充分利用两个世界 - 使用枚举,方便和可读性,并允许任意扩展。

@ user3047395

很难给出确切的建议,因为这不是我的代码。我个人倾向于避免使用这种东西的枚举,因为我更喜欢用它们的依赖构造我的对象而不是通过方法传递它们。但是,为了轻松转换到State模式,您可以从具有传递BankRobber的方法的接口开始,因此它可以查询属性并返回新状态或返回自身。