java - super 和覆盖的问题 - 更好的方法吗?

标签 java architecture groovy

我在使用 super 和覆盖方面遇到了问题。基本上,扩展 A 的类 B 有一个用于类当前状态的 setter 。在 setter 内部,根据当前状态的值,可以执行不同的事件。

B 的 setter 中发生的第一件事是调用 super 以便 A 的 setter 可以启动一般事件.然后控件返回到 B 的 setter,如果需要我可以在其中执行特定事件。

A 执行调用 setter 的事件时,问题就来了,因此它可以在返回到 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

当我在调用 super(“After super for...”)后回到 B 时,num 的值是总是一样的,这意味着它与我在 B 中尝试做的事情有关(即启动特定事件)。

架构的一些要点:

  • “为什么不在 B 的 setter 中使用 i 而不是 num”? - 这只是显示问题的最简单示例 - 我的代码中实际发生的情况不同,只是同一个问题。在我的例子中,我可以访问 num,而不是 i。即使我重写了它的一部分以通过 i,类的状态也会继续(由于基类)
  • 这是一个服务器环境,所以我无法访问帧循环或类似的东西。它是基于事件的。
  • 应该可以异步执行事件,或者将事件设置为稍后安排,但这需要大量关于事件将在何时何地使用的预先知识,这打破了事件的全部意义第一名

我正在寻找的是一种根据类的状态启动事件的方法,但如果是的话,它是否会在 super 返回后发生(同时仍在为基类工作)有任何意义。

想法?

编辑

为了更好地了解我正在使用的代码(根据 Don 关于使用回调的建议),这里是我所拥有的代码的简化版本。 (如果你想运行它,你可以将它复制到 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,因为在某些状态下我需要一个基本的 plus 特定事件。基本事件通常用于设置程序状态,而特定事件用于响应。

在这个例子中,我的输出是:

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 使用react

编辑

如果我将 B 中的 super() 调用更改为 _onStateChanged() 的末尾而不是开始,这将给出它有机会在状态改变之前对状态使用react。这是解决这个问题的简单方法,还是错误的?

编辑 所以我想到了这个(同样,您可以将它复制到 groovy console appspot 站点):

// 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

但是有点丑。更好的方法?

最佳答案

从根本上说,A.setFoo 被破坏了

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 );
    }
}

因为new A().setFoo(2)(举例)会造成栈溢出。像下面这样的东西可能是一个更好的设计

abstract class A
{
    public int num = 0;

    abstract void setFooCallback(int i)

    public final 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.setFooCallback( num );
    }
}

class B extends A
{
    public void setFooCallback( int i ) 
    {
        // Implement me to launch custom events or whatever
        // If you call setFoo in here you'll get a stack overflow
    }
}

如果您需要实例化 A 的实例,只需删除 abstract 修饰符并将 setFooCallback 更改为:

void setFooCallback(int i) { // default implementation does nothing }

仅供引用,我认为以上是模板(方法)模式的示例

关于java - super 和覆盖的问题 - 更好的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6650512/

相关文章:

string - 如何在Groovy中将列表转换为字符串并删除括号而不使用replace?

java - 在 gradle 中完成任务后添加消息或下一行

gradle - 如何在build.gradle中定义和调用自定义方法?

Java 向设备发送 MIDI 消息

http - 协议(protocol)不可知服务器的架构设计

java - Hippo CMS - 在每次重新加载页面时显示随机新闻提要

WCF 设计 - 一个请求和响应对象还是多个?

rest - 使用 Play 2.1 作为后端构建 AngularJS 客户端代码的好方法

java - 从 javadoc 绘制接口(interface)和类图的程序

java - Hibernate 级联引用约束冲突