2011-06-23 67 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

臭虫,尼克打我:) –