C# 人们如何绕过需要不同数量的参数的超类的子类init方法?

C# 人们如何绕过需要不同数量的参数的超类的子类init方法?,c#,java,actionscript-3,oop,C#,Java,Actionscript 3,Oop,假设我有一个带有基本实体类的游戏,带有一个不带参数的init方法。现在我有一个向导类,但我想传入两个参数,比如速度和强度。在AS3中(我相信Java和C#),我不允许这样做——这是一种“不兼容的覆盖”,因为方法签名不匹配。现在我可以只做一个“initWizard”方法,但是我有一个问题,每个类的init方法可能有不同的名称 我需要在AS3、Java或C#中工作的解决方案。我不确定我是否正确理解了您的问题。但以下代码是用Java编译的: public class A { public vo

假设我有一个带有基本实体类的游戏,带有一个不带参数的init方法。现在我有一个向导类,但我想传入两个参数,比如速度和强度。在AS3中(我相信Java和C#),我不允许这样做——这是一种“不兼容的覆盖”,因为方法签名不匹配。现在我可以只做一个“initWizard”方法,但是我有一个问题,每个类的init方法可能有不同的名称


我需要在AS3、Java或C#中工作的解决方案。

我不确定我是否正确理解了您的问题。但以下代码是用Java编译的:

public class A {
    public void init(int a) {}
}

public class B extends A {

    public void init( int a, int b )
    {
        super.init( a );
    }
}
虽然我同意
B#init(int,int)
不是
A#init(int)
的重写,而且
B#init(int)
仍然可以调用。您不能真正隐藏
B#init(int)
的存在,充其量,您可以在
B
中重写它,并让它在调用时抛出异常

然而,这是一个大问题吗?方法签名只捕获类必须如何使用的契约的一部分。如果您想进一步屏蔽代码,可以使用工厂方法创建
a
B
的实例,并使
init
受到保护

public class A {
    protected void init(int a) {}

    static public A create( int a)
    {
        A o = new A();
        o.init( a );
        return o;
    }
}

public class B extends A {

    protected void init( int a, int b )
    {
        super.init( a );
    }

    static public B create( int a, int b)
    {
        B o = new B();
        o.init( a, b );
        return o;
    }
}

AS3不支持方法重载,但坦率地说,方法重载只是一种语法糖,通常只会引入歧义和不一致性

在Java中,方法由其名称和签名决定,在AS3中,仅由其名称决定,但在语义上,它们之间的差别很小

protected void init( int a )
protected void init( int a, int b )

在AS3中,每个名称只能有一个方法,每个类只能有一个构造函数。但是,构造函数不需要具有兼容的签名。在AS3中,您可以这样解决问题:

package {
 class A {
  private var a:int;
  public function A(a:int) {
   this.a = a;
  }
  // ... probably some meaningful methods here :)
 }
}
package {
 class B extends A {
  private var b:int;
  public function B(a:int, b:int) {
   super(a);
   this.b = b;
  }
  // ... probably some other meaningful methods here as well :D
 }
}
您还可以避免ewernli提供的Java解决方案中的问题

编辑:刚刚看到,您坚持不使用构造函数,而是使用具有不同签名的init方法。为什么?这违反了法律

edit2: 我想你有两个选择:

  • 初始值设定项的不同名称(不是最好的想法,也因为您的子类将公开初始值设定项,它们只能部分工作(不好,请参阅上面提到的LSP))
  • 生活在哲学中,任何阶级都必须是抽象的或最终的。示例(假设一个太空游戏):
  • 抽象基类,多个具体子类:

    class ShipBase {//in Java you might wanna put the 'abstract' keyword just infront
     //... implementation of some sort
     //... maybe a protected intializer to call by subclasses
     //... no public initializer, since class is abstract
    }
    final class Fighter extends ShipBase {
     //... public initializer specific to Fighter
     //... other custom behaviour
    }
    final class Bomber extends ShipBase {
     //... I guess, this is obvious
    }
    
    现在您可能会问自己:如果我希望
    Fighter
    成为一个基类(比如说,
    EliteFighter2000
    ),但同时也是一个可实例化的类,该怎么办。简单。只是不必这样

    class FighterBase extends ShipBase {
        //... implementation of whatever kind of things fighters have in common
        //... a protected intializer to call by subclasses    
    }
    final class Fighter extends FighterBase {
        //... public initializer possibly just forwarding to protected initializer
    }
    final class EliteFighter2000 extends FighterBase {
        //... here goes all the 'elite' stuff
    }
    
    这也更加灵活。现在,您可以更改简单的
    战斗机
    ,而不影响
    精英战斗机2000
    ,也可以通过修改
    战斗机基地
    ,决定要更改所有战斗机的常见行为。继承通常是一件危险的事情,经常被误解和误用。
    坚持这条规则通常有助于避免由于缺乏关注点的分离而导致的微妙的、但往往影响深远的耦合继承。在这种情况下,战斗机通用的任何东西都将在
    FighterBase
    中实现,而简单的
    战斗机专用的任何东西都会在它所属的地方实现

    格里茨

    back2dos

    我认为这在c#和Java中不是一个问题。构造函数属于它们的类并且不会被重写,相反,子类将使用适当数量的方法调用一个超类的构造函数。问题似乎是3特定的,所以您应该这样标记。不是我的错误-构造函数可以有不同数量的参数-仍然需要init方法的答案。在Java中,您可以创建多个名称相同但参数数量不同的方法,或者数量相同但类型不同的方法。根据参数的数量及其类型,将调用相应的方法。在您的示例中,init In向导不会覆盖init In实体。Wizard只是有一个实体没有的方法。谢谢这个-基本上我只是想知道我是疯了还是AS3遗漏了一些重要的东西。这一次的答案是AS3缺少了一些重要的东西,所以我可以使用对象池-需要能够重新初始化对象,就像它们是新的一样。
    class FighterBase extends ShipBase {
        //... implementation of whatever kind of things fighters have in common
        //... a protected intializer to call by subclasses    
    }
    final class Fighter extends FighterBase {
        //... public initializer possibly just forwarding to protected initializer
    }
    final class EliteFighter2000 extends FighterBase {
        //... here goes all the 'elite' stuff
    }