这种继承方式错了吗?

时间:2012-02-10 18:33:03

标签: ruby oop inheritance composition aggregation

我不知道我是否选择了一个好的冠军,但我正在开发一个简单的基于卡片的游戏,这是我的场景:

我有一个名为 Player 的类,我已经从Player中实例化了几个对象(比方说4)。在每一轮比赛中,我们都会有一种特殊类型的玩家可以说 SpecialPlayer ,在每一轮中,这4名玩家中的一个可以是SpecialPlayer。

SpecialPlayer是一个简单的玩家,它可以做更多的东西,让我们说停顿/重启游戏。所以我继承了Player并创建了SpecialPlayer并为该类添加了2个方法。 问题是,当我实例化SpecialPlayer时,我会有另外一个对象加上那4个玩家对象,那就好了,但是我希望能够在SpecialPlayer中更改属性,并在该轮上看到对作为SpecialPlayer的Player对象的效果

例如,每个玩家都可以得分,我想看到SpecialPlayer得分,并改变得分及其对玩家对象的影响。

这里的继承是错的吗?我必须在SpecialPlayer类中编写Player类吗?

如果它可能改变答案,我不得不说我正在使用 Ruby

4 个答案:

答案 0 :(得分:2)

由于SpecialPlayer对象应该在每轮结束时替换一个Player对象,我认为最好不要创建一个SpecialPlayer类来扩展Player。

我会向播放器添加一个标志,将其标记为特殊(布尔特殊),并据此我知道他是否可以执行特殊功能。

答案 1 :(得分:1)

这听起来像是Decorator模式的工作。您可以使用与常规Player类相同的接口(IPlayer)创建SpecialPlayer类。 SpecialPlayer类还有一个player属性(指向特殊玩家的指针)和一个assignPlayer方法,该方法在每一轮结束时调用,将player属性设置为指向新特殊玩家的指针。继承自IPlayer的SpecialPlayer类的所有方法都应该从player属性调用相应的方法。

答案 2 :(得分:1)

我将不得不与其他人意见不一致,并告诉您这听起来像是需要使用Player模块扩展您的SpecialPlayer 实例。让我来证明一下。假设你有一个玩家类:

class Player
  attr_accessor :game

  def special?
    false
  end
end

所有玩家都将拥有这些方法。让我们创建一个新玩家:

player = Player.new
player.game = Game.new
player.special? # false

现在假设你有SpecialPlayer模块:

module SpecialPlayer
  def special?
    true
  end

  def pause_game
    game.pause
  end

  def restart_game
    game.restart
  end
end

您的模块尚未改变Player行为,因为您没有对播放器做任何事情。所以让我们用SpecialPlayer扩展我们的播放器实例:

player.extend SpecialPlayer
player.special? # true
player.pause_game # pauses the game
player.restart_game # restarts the game

这样做的好处是,系统中的任何其他玩家都不必关心谁是特殊的或者他们是如何做到的那样:

other_player = Player.new
other_player.special? # false
other_player.pause_game # NoMethodError: undefined method `pause_game' for #<Player>
other_player.restart_game # NoMethodError: undefined method `restart_game' for #<Player>

这也确保了不仅任何玩家都可以是特殊的。从非特殊玩家调用#restart_game甚至不会起作用,所以你不会有常规玩家正在做他们不应该做的事情的错误。

答案 3 :(得分:0)

基本上,您希望Player的行为取决于它是否特殊。在这种类型的问题中,将变化的行为封装在接口(IHandling)中并让原始类依赖于该接口的实现是有用的。在您的情况下,您可以让Player委托的行为改变为SpecialHandlingNormalHandling。你的正常处理无能为力。每轮结束后,SpecialHandling对象可以附加到另一个Player

点应存储在Player类中,因为这是常用功能。但是,假设使用PlayerSpecialHandling乘以点,您可以让Player类将此委托给IHandling实例。