Почему этот 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 ":("
}
}
Это была моя модификация шаблона популярного штата, но, к сожалению, не работает: оператор присваивания в абстрактном классе вызывается в начале каждого конструктора класса, наследующего его. Поэтому оператор присваивания пытается создать объект производного класса. т.е. Actor a = new HappyActor()
вызывается, когда вызывается конструктор класса 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)
Возможно ли реализовать такое изменение состояния с помощью наследования. Я нашел это в книге Брюса Эккеля " Думая на Java". Напротив, вы не можете решить наследовать по-разному во время выполнения; которые должны быть полностью определены во время компиляции
Избавьтесь от переменной класса. Ваши методы должны выглядеть так:
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();
}
}
Поэтому я сделал это так, согласно предложению Анони-Муса:
// 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 :)
}
}
Это лучшее, что я мог сделать!
Во втором примере кода, который действительно является правильным, Actor является "State" Stage. (Возможно, Актер, будучи настолько независимым от Сцена, больше похож на Стратегию, но на этом уровне сложности разница не имеет смысла.)
Вы хотите сделать что-то еще?
Подумайте, что происходит, когда вы HappyActor
создать свой первый HappyActor
. По умолчанию ctor нужно сначала создать кишки Actor
, и первое, что делает, пытается построить HappyActor
. Бум, бесконечная рекурсия.