想象一下,我有一個帶有基本實體類的遊戲,帶有一個不帶任何參數的init方法。現在我有一個嚮導類,但我想傳遞兩個參數,比如速度和力度。在AS3(我相信Java和C#)我不會被允許這樣做 - 它是「不兼容的重寫」,因爲方法簽名不匹配。現在我可以創建一個「initWizard」方法,但是我有每個類的init方法可能具有不同名稱的問題。人們如何繞過需要不同數量的參數到其超類的子類init方法?
我需要在AS3,Java或C#中工作的解決方案。
想象一下,我有一個帶有基本實體類的遊戲,帶有一個不帶任何參數的init方法。現在我有一個嚮導類,但我想傳遞兩個參數,比如速度和力度。在AS3(我相信Java和C#)我不會被允許這樣做 - 它是「不兼容的重寫」,因爲方法簽名不匹配。現在我可以創建一個「initWizard」方法,但是我有每個類的init方法可能具有不同名稱的問題。人們如何繞過需要不同數量的參數到其超類的子類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錯過了一些重要的東西。這一次的答案是AS3缺少一些重要的東西。 – Iain 2010-08-10 10:40:47
AS3不支持方法重載,但坦率地說,方法重載只是一個語法糖,通常只介紹不確定性和不一致性。
在Java中,一個方法是由它的名字和它的簽名確定,在AS3中,只有它的名字,但語義,這裏只有
protected void init(int a)
protected void init(int a, int b)
和
protected void init1(int a)
protected void init2(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方法。爲什麼?這違反了Liskov substitution principle。
EDIT2: 我想你有2種選擇:
一個抽象基類,多個具體的子類:
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
}
這也比較靈活。您現在可以更改簡單Fighter
而不影響EliteFighter2000
,或者您可以決定通過修改FighterBase
來改變所有戰士的常見行爲。繼承通常是一件危險的事情,經常被誤解和誤用。
堅持這個規則通常有助於避免微妙的,但往往相當深遠的耦合繼承可以通過缺乏關注分離引入。在這種情況下,戰鬥機常見的任何事情都將在FighterBase
中執行,任何特定於簡單Fighters
的事物都可以在其所屬的位置進行。
格爾茨
back2dos
我不認爲這是在C#和Java的問題。構造函數屬於它們的類,並且不會被重寫,而是一個子類將使用適當數量的方法調用超類的構造函數。 問題似乎AS3具體,所以你應該標記它。 – Kurt 2010-08-10 09:32:31
不是我的錯誤 - 構造函數可以有不同數量的參數 - 但仍然需要init方法的答案。 – Iain 2010-08-10 09:35:03
在Java中,您可以使用相同的名稱創建多個方法,但參數個數不同,或者編號相同但類型不同。根據參數的數量及其類型,調用適當的方法。 在您的示例中,嚮導中的init不會覆蓋實體中的init。嚮導只有一個Entity沒有的方法。 – Kwebble 2010-08-10 10:10:59