Java 具有不同实现的状态模式导致难以理解的错误

Java State Pattern with different implementation resulting in a difficult to understand error

为什么这个 java 代码不起作用。

abstract class Actor {
    Actor a = new HappyActor();
    abstract void act();
    void change() { a = new SadActor(); }
    void go() { a.act(); }
}

class HappyActor extends Actor {
    public void act() {
        System.out.println( ":)" );
    }
}

class SadActor extends Actor {
    public void act() {
        System.out.println( ":(" );
    }
}

public class TransmogrifyMe {
    public static void main( String[] args ) {
        Actor s = new HappyActor();
        s.go(); // Prints ":)"
        s.change();
        s.go(); // Prints ":("
    }
}

这是我对流行的状态模式的修改,但不幸的是没有用: 抽象 class 中的赋值语句在每个继承它的 class 构造函数的开头调用。所以赋值语句试图创建一个派生的对象class。即 Actor a = new HappyActor() 在 class HappyActor 的构造函数被调用时被调用,这导致构造函数调用永无止境的循环。真的是这样吗?

工作版本类似于下面的代码:

abstract class Actor {
    abstract void act();
}   

class HappyActor extends Actor {
    public void act() {
        System.out.println( ":)" );
    } 
}   

class SadActor extends Actor {
    public void act() {
        System.out.println( ":(" );
    } 
}   

class Stage {
    Actor a = new HappyActor();
    void change() { a = new SadActor(); }
    void go() { a.act(); }
}   

public class Transmogrify {
    public static void main( String[] args ) {
        Stage s = new Stage();
        s.go(); // Prints ":)"
        s.change();
        s.go(); // Prints ":("
    }
}

第一个代码中产生的错误消息是这两行的无限循环:

at Actor.<init>(TransmogrifyMe.java:6)
at HappyActor.<init>(TransmogrifyMe.java:12)

是否可以使用继承来实现这种状态变化。我在 Bruce Eckel 的书中找到了这个 Thinking in Java In contrast you can't decide to inherit 运行 时间不同;必须在编译时完全确定

想一想当您尝试创建第一个 HappyActor 时会发生什么。默认的 ctor 需要首先创建 Actor 的核心,而要做的第一件事就是尝试构建 HappyActor。繁荣,无限递归。

在第二个代码示例中,确实正确,Actor是Stage的"State"。 (也许 Actor 如此独立且独立于 Stage,更像是一种 Strategy,但在这种复杂程度下,差异是没有意义的。)

你还想做点别的吗?

删除 class 变量。您的方法应如下所示:

State doSomething() {
  // do something, e.g. println.
  return new NextState();
  // or return this to stay in the current state.
}

然后像这样使用它们:

state = state.doSomething();

即你 return 下一个 状态。

例如

class HappyState implements State {
  public State change() {
    return new SadState();
  }
}

于是我就按照Anony-Mousse的建议这样做了:

// StateChange.java
// Implementing the state pattern using inheritance

interface State {
    public State change();
    public void print();
}

class SadState implements State {
    public State change() {
        return new SadState();
    }
    public void print() {
        System.out.println( ":(" );
    }
}
class HappyState implements State {
    public State change() {
        return new SadState();
    }
    public void print() {
        System.out.println( ":)" );
    }
}

public class StateChange {
    public static void main( String[] args ) {
        State h = new HappyState();
        h.print(); // prints :)
        h = h.change();
        h.print(); // prints :(
        h = h.change();
        h.print(); // prints :)
    }
}

我已经尽力了!