2011-06-23 107 views
1

我有一系列的類和一些推廣:Java的擴展問題

Class Base1{ .... } 

Class Base1Extend1 extends Base1 {.....} 

Class Base1Extend2 extends Base1 {......} 

我現在有另一套使用這些:

Class Base2 { 
    Base1 base1; 
    } 

Class Base2Extend1{ 
    base1 = new Base1Extend1();} 

Class Base2Extend1{ 
    base1 = new Base1Extend2();} 

現在,和Base2執行對基礎1的實例化一些工作。

此外,Base2Extend1和Base2Extend2需要在其特定擴展類上執行工作。例如,它們調用僅存在於子類中的特定方法。有沒有辦法做到這一點,而不必每次都在Base2的擴展類中使用cast?


確切的情況是這樣的:

這是一種紙牌遊戲,其中有2種類型的球員:用戶和「計算機」。 有很多適用於它們的基本方法(pickup卡(),discardCards()等)。 然後有特定於用戶的方法(checkMove()等)以及特定於「計算機」(doTurn()等)的方法。

接下來是保存用戶卡片的對象playerHand。 同樣有基本的方法來處理手(addCards(),removeCards()等)。 然後,只有用戶手中有特定的方法(checkCards()等)以及那些特定於「計算機」(判定WhatToDo()等)的方法。

現在我想,也許這會更簡單地將類合併在一起。 將Base1和Base2合併到一個類中,然後對子類進行等效合併。

+0

'class Java extends Question'?嗯... – mre

+0

命名爲'Base2Extend2擴展Base1'是否正確? – oliholz

+0

你想知道是否有一個類可以像C++中的另一個類似的「朋友」? –

回答

4

在這種情況下,您必須每次都施放,或者創建更具體類型的字段/變量。

我不確定你在哪裏,但要小心這個設計。通常這是一個表明你錯誤地使用了繼承。

如果您需要在子類上調用新方法,因爲它需要它在超類中定義的某個任務,這意味着該子類違反了其父協議(Google Liskovs替代原理)。

如果子類確實具有一些不與父類交互的新功能,您可能希望從一開始就明確使用該子類(即變量聲明)。或者,如果它沒有真正相關,那麼您可能應該使用全新的類和組合而不是繼承。


這是相當寬泛的,但這種卡片遊戲的設計如何。我認爲這是一個有幾回合的詭計多端的遊戲,需要檢查一個動作是否有效以及誰接受這個動作。我不確定你的意思是棄牌,添加或移除牌。

  • 製作一個Player類,但它不會比名稱更多。它也可以有一個卡集合。
  • 另一個類是GameController,它負責協調正在發生的事情並檢查規則。它可能有這樣的方法,如:
    • playCard(播放器,卡),驗證移動,並添加卡到竅門記住誰播放它。
    • score()計算每回合結束時的分數。
  • 另一個類是CPUController。這就是人工智能所在的地方。
  • 最後,一個主循環。

主迴路可以工作是這樣的:

controller.shuffle(); 
// Either of: 
// 1. push: controller.shuffle() calls player.pickupCards(cards) 
// 2. pull: main loop calls player.pickupCards() which in turn calls controller.giveMeMyCards() 

while(playersHaveMoreCards()) { 
    awaitPlayerMove(); 
    // Now is the only time when player can make a move. If there is some 
    // GUI the main loop could `wait()` on a mutex (until it's awoken when 
    // player makes move), in text mode it could simply await input from keyboard. 

    // When player makes a move, it calls controller.playCard(player, card) 

    cpuController.move(); 
    // Again, when it controller calculates its move, eventually it simply calls controller.playCard() 

    controller.score(); 
} 
announceWinner(controller.getScore()); 

現在,這裏是你獲得這種方法是什麼:

  • 到遊戲規則和得分相關的所有東西都在一個地方,這是GameController中唯一的東西。這很容易掌握和維護。
  • CPU AI也是如此。這一切都在一個地方,而CPUController中唯一的東西就是AI實現。
  • 從外部控制器是完全一樣的,無論你有人類與CPU,CPU與CPU還是人類與人類。如果你想要多人遊戲,那麼你在這裏改變的唯一的東西就是主循環(這是一個微不足道的變化)。
  • 如果你想實現另一個詭計遊戲,你可能唯一會改變的是GameController(不同的規則)和CPUController(不同的AI)。
  • 如果你想要AI的另一個實現(比如更智能的算法),你可以通過替換CPUController來實現。

最後兩種情況是繼承有意義的地方。你希望CPUController和GameController具有相同的接口(當然每個接口都不相同),這樣主循環和播放器就可以與控制器的不同實現無縫地協作。

如果您想了解有關這些設計原則的更多信息,請參閱Google for SOLID。全都是這個例子。 :-)

+0

我只是在問題中增加了一些細節,並想知道這是否是正確的方法。 – theblitz

+0

@theblitz查看更新的答案。 –

+0

遊戲不是一個絕招 - 它是一個丟棄/拾取遊戲。事情是,在某些情況下,如果AI還沒有移動,用戶可以在移動後再次移動。出於這個原因,我不得不將它從循環中取出,並讓它由UI和/或postDelayed驅動。當玩家輪到他們時,每個玩家將控制權交給下一個控制器,而不是循環。 – theblitz

1

不,沒有。您必須執行強制轉換,否則編譯器無法確定函數是否存在。

如果子類的功能是相同的,那麼你可以在接口中實現它們,讓子類實現它們並擴展基類。然後,您可以簡單地投射到界面,但仍然必須執行投射。

+0

請注意,使用泛型時會執行演員表演,但不能由開發人員明確進行。 – Nick

1

爲了避免鑄件,想想泛型:

class Base2<T extends Base1> { T base1; } 

// base1 does not need to be cast to Base1Extends1 
class Base2Extends1 extends Base2<Base1Extends1> { base1 = new Base1Extends1(); } 

// base1 does not need to be cast to Base1Extends2 
class Base2Extends2 extends Base2<Base1Extends2> { base1 = new Base1Extends2(); } 
0

你可能想用參數例如類,使用字段T base1。然後編譯器知道你正在使用T => Base1Extend1或Base1Extend2,並且你不必投射。

+0

臭蟲,尼克打我:) –