2010-08-10 44 views
3

想象一下,我有一個帶有基本實體類的遊戲,帶有一個不帶任何參數的init方法。現在我有一個嚮導類,但我想傳遞兩個參數,比如速度和力度。在AS3(我相信Java和C#)我不會被允許這樣做 - 它是「不兼容的重寫」,因爲方法簽名不匹配。現在我可以創建一個「initWizard」方法,但是我有每個類的init方法可能具有不同名稱的問題。人們如何繞過需要不同數量的參數到其超類的子類init方法?

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

+0

我不認爲這是在C#和Java的問題。構造函數屬於它們的類,並且不會被重寫,而是一個子類將使用適當數量的方法調用超類的構造函數。 問題似乎AS3具體,所以你應該標記它。 – Kurt 2010-08-10 09:32:31

+0

不是我的錯誤 - 構造函數可以有不同數量的參數 - 但仍然需要init方法的答案。 – Iain 2010-08-10 09:35:03

+0

在Java中,您可以使用相同的名稱創建多個方法,但參數個數不同,或者編號相同但類型不同。根據參數的數量及其類型,調用適當的方法。 在您的示例中,嚮導中的init不會覆蓋實體中的init。嚮導只有一個Entity沒有的方法。 – Kwebble 2010-08-10 10:10:59

回答

1

不知道我是否正確理解你的問題。但在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中覆蓋它,讓它在被調用時拋出一個異常。

然而這是一個大問題嗎?方法簽名僅捕獲如何使用類的合約的一部分。如果您想更多地屏蔽代碼,可以使用工廠方法創建AB的實例,並使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; 
    } 
} 
+0

感謝你 - 基本上我只是想知道我是瘋了還是AS3錯過了一些重要的東西。這一次的答案是AS3缺少一些重要的東西。 – Iain 2010-08-10 10:40:47

6

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種選擇:

  1. 不同的名稱爲您初始化(不是最好的想法,也因爲你的子類會暴露初始化,只有部分工作(並不好,見上面提到的LSP))。
  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

+0

所以我可以使用對象池 - 需要能夠重新初始化對象,就像它們是新的一樣。 – Iain 2010-08-10 11:26:30

+0

@Iain:帖子已更新 – back2dos 2010-08-10 11:59:06

相關問題