У меня проблема с использованием super и overriding.По сути, класс B
, который расширяет A
, имеет установщик текущего состояния класса.Внутри установщика, в зависимости от значения текущего состояния, может выполняться другое событие.
В установщике для B
первое, что происходит, это то, что он вызывает super
, так что установщик дляA
может пойти запустить общие события.Затем элемент управления возвращается к установщику B
, где я могу при необходимости выполнить определенные события.
Проблема возникает, когда A
выполняет события, вызывающие установщик, и поэтому он может пройти несколько глубин, прежде чем вернуться обратно кна B
.
Следующий код иллюстрирует то, о чем я говорю (это классно, но не имеет значения):
class A
{
public int num = 0;
public void setFoo( int i )
{
println "A: $i";
num = i + 1;
// what's actually happening, is that in the setter, depending
// on the value, an event can be executed, which will in turn
// call setFoo() on the class. this is just the equivalet
if( i < 3 )
this.setFoo( num );
}
}
class B extends A
{
public void setFoo( int i )
{
println "B: $i - num $num";
super.setFoo( i );
println "After super for $i - num: $num";
}
}
def B = new B();
B.foo = 0;
В результате получается:
B: 0 - num 0
A: 0
B: 1 - num 1
A: 1
B: 2 - num 2
A: 2
B: 3 - num 3
A: 3
After super for 3 - num: 4
After super for 2 - num: 4
After super for 1 - num: 4
After super for 0 - num: 4
Когда я возвращаюсь к B
после вызова super
(«После супер для ...»), значение num
всегда одинаково, что означает, что он привинчивает к тому, что япытается сделать в B
(то есть запускать определенные события).
Некоторые пункты архитектуры для начала:
- "Почему бы не использовать
i
вместо num
в сеттер для B
"?- Это просто самый простой пример, чтобы показать проблему - то, что на самом деле происходит в моем коде, отличается, просто та же самая проблема.В моем случае у меня есть доступ к num
, а не i
.Даже если я переписал часть этого кода для передачи i
, состояние класса будет изменено (из-за базового класса) - Это серверная среда, поэтому у меня нет доступа к кадрупетля или что-то подобное.Это основано на событиях.
- Должна быть возможность асинхронно выполнить событие или настроить событие на более позднее расписание, но для этого требуется много предварительных знаний о том, где и когда будет использоваться событие, котороев первую очередь разбивает весь смысл событий
Мне нужен способ запуска событий, основанный на состоянии класса, но произойдет ли это после возврата из super
(все еще работая для базового класса), если это имеет какой-то смысл.
Идеи?
РЕДАКТИРОВАТЬ
Чтобы дать лучшее представление о кодеЯ использую (основываясь на предложении Дона использовать обратный вызов), вот упрощенная версия того, что у меня есть.(Если вы хотите запустить его, вы можете просто скопировать его в http://groovyconsole.appspot.com/):
// A is our base class
class A{
public int currentState= 0;
public void setCurrentState( int i )
{
this.currentState = i;
this._onStateChanged();
}
protected void _onStateChanged()
{
println "The state in A is $currentState";
// depending on the state launch some events.
// these can changed the current state of
// B
if( this.currentState == 0 )
{
def event = new MyEvent( this );
event.execute();
}
}
}
// B is a more specific version of A
class B extends A
{
protected void _onStateChanged()
{
println "The state in B is $currentState";
super._onStateChanged();
println "The state in B afterwards is $currentState";
// launch specific events based on the current state
if( this.currentState == 0 )
println "Launch a specific event!";
}
}
// simple event class that can change the status of B
class MyEvent
{
private B b = null;
public MyEvent( B b )
{
this.b = b;
}
public void execute()
{
// do some stuff
b.currentState++;
}
}
// program start
def b = new B();
b.currentState = 0;
B
должен вызвать super
, так как есть некоторые состояния, где я хочу базовый плюс конкретное событие. Базовые события обычно используются для установки состояния программы, в то время как конкретные реагируют на них.
В этом примере мой вывод:
The state in B is 0
The state in A is 0
The state in B is 1
The state in A is 1
The state in B afterwards is 1
The state in B afterwards is 1
т.е. Bникогда не реагирует на состояние 0
Edit
Если я изменю вызов super()
в B
на конец _onStateChanged()
, а не наначать, это даст ему возможность среагировать на состояние до того, как оно будет изменено. Это простое решение этой проблемы или просто неправильно?
Редактировать Итак, я придумалэто (опять же, вы можете скопировать его на сайт приложения Groovy для консоли):
// A is our base class
class A{
public int currentState = 0;
public int nextState = 0;
public boolean canChange = true;
public void setCurrentState( int i )
{
if( this.canChange )
{
this.currentState = i;
this._onStateChanged();
}
else
this.nextState = i;
}
protected void _onStateChanged()
{
println "The state in A is $currentState";
// depending on the state launch some events.
// these can changed the current state of
// B
if( this.currentState == 0 )
{
def event = new MyEvent( this );
event.execute();
}
}
}
// B is a more specific version of A
class B extends A
{
protected void _onStateChanged()
{
this.canChange = false;
println "The state in B is $currentState";
super._onStateChanged();
println "The state in B afterwards is $currentState";
// launch specific events based on the current state
if( this.currentState == 0 )
println "Launch a specific event!";
this.canChange = true;
if( this.nextState != 0 )
{
int state = this.nextState;
this.nextState = 0;
this.currentState = state;
}
}
}
// simple event class that can change the status of B
class MyEvent
{
private B b = null;
public MyEvent( B b )
{
this.b = b;
}
public void execute()
{
// do some stuff
b.currentState++;
}
}
// program start
def b = new B();
b.currentState = 0;
Это дает мне желаемый результат:
The state in B is 0
The state in A is 0
The state in B afterwards is 0
Launch a specific event!
The state in B is 1
The state in A is 1
The state in B afterwards is 1
но это уродливо. Лучше?