2014-01-10 42 views
0

我有一個設計問題,我似乎無法弄清楚。我正在實施一款紙牌遊戲,而且我正在爲如何組織紙牌結構而苦苦掙扎。遊戲中的每張牌都有一些共同的行爲,這意味着卡應該是基礎類。刪除接口的冗餘實現而不使用繼承

但是,每張卡片可以是硬幣,法力或健康卡。最重要的是,任何卡都可以是這三種類型的組合。我最初的想法是讓硬幣,法力和健康每一個接口,然後我將能夠實現與培訓相關的接口,像這樣的卡片:

public class SomeCard extends Card implements Coin, Mana { 

} 

通過這種方式,所有繼承類將有基卡行爲並實施必要的行爲。問題出現在三個接口中的每一個內都有一些共享的行爲。例如Coin就有一個getWorth()函數,它對於所有的硬幣卡基本上都是一樣的。如果我具有相同的確切功能&實現,那麼應該有一種方法來抽象出冗餘。這只是冗餘的一個例子。

public class CardA extends Card implements Coin { 
    public int getWorth(){ 
     return worth; 
    } 

    //Other inherited or implemented methods 
} 

public class CardB extends Card implements Coin, Health { 

    public int getWorth(){ 
     return worth; 
    } 

    //Other inherited or implemented methods 
} 

不幸的是,因爲錢幣是一個接口,所以沒有辦法減少所有卡上的冗餘。有一種方法可以在應用Coin,Mana,Health類型或這些類型的組合的情況下移除冗餘代碼?

我想避免這樣的事情:

public class SomeCard extends CoinManaCard { 

} 

我覺得上面的將是一個非常糟糕的實現,因爲無論何時添加了新的類型會有的類型更多的組合和維護將是顯著。

感謝您的幫助!

+2

你是什麼尋找接口的默認實現,這將在Java 8中可用。 – chrylis

+0

是應該這樣做的。謝謝! – johnsoe

回答

0

共享行爲可以移動到超類。如果由於某種原因無法修改卡片,則可以引入其他級別的繼承 - 在我的環境中,我們通常將其稱爲BaseCard--它實現卡片的所有方法(您可以在特定卡類),或者它是一個abstract class,所以它可以實現共享行爲,並讓其他人通過派生類實現。然後,您的實際CardA,CardB等將擴展BaseCard,這也將使它們成爲卡片。 (注意,當你使用「抽象」這個詞時,你幾乎可以自己回答這個問題,當你想分解出共享行爲時,另一層繼承是實現它的一種方式,而抽象類是一種好方法保持相對容易,並明確表示你不打算直接使用它們。)

另一種解決方案是委託 - 將is-a關係更改爲has-a,讓每個卡片擁有一個實例提供共享功能的實用程序類,並讓該卡的方法調用該實用程序類的方法來完成這項工作。同樣,這可以讓你分解出一組邏輯,但是這完全獨立於繼承。效率稍差,但這是一個非常合理的解決方案。如果你需要從幾個不同的類中獲取行爲,這是唯一的解決方案,因爲Java只允許接口的多重繼承,而不是類(即使它們是抽象的) - 一個超類(無論它有什麼繼承),再加上儘可能多的接口是有意義的。

(如果你想知道爲什麼Java有這種限制,查找「鑽石繼承」。簡單的答案是它可以非常快速地變得非常混亂,甚至在支持它的語言中,人們通常會使用更像Java的單繼承加接口加代表模型的東西。)