【问题标题】:is this way of inheritance wrong?这种继承方式错了吗?
【发布时间】:2012-03-03 05:23:03
【问题描述】:

我不知道我是否选择了一个好的标题,但我正在开发一个简单的卡牌游戏,这是我的场景:

我有一个名为 Player 的类,并且我从 Player 实例化了几个对象(比如说 4 个)。在每一轮游戏中,我们都有一种特殊类型的玩家,可以说 SpecialPlayer,在每一轮中,这 4 名玩家中的一个都可以成为 SpecialPlayer。

SpecialPlayer 是一个简单的播放器,而且它可以做更多的事情,比如暂停/重启游戏。所以我从 Player 继承并创建了 SpecialPlayer 并向该类添加了 2 个方法。 问题是,当我实例化 SpecialPlayer 时,我将有另一个对象加上这 4 个玩家对象,没关系,但我希望能够更改 SpecialPlayer 中的属性并查看该回合中作为 SpecialPlayer 的 Player 对象的效果

例如每个 Player can Score points ,我想看到 SpecialPlayer 得分并更改分数及其对 Player 对象的影响。

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

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

【问题讨论】:

    标签: ruby oop inheritance composition aggregation


    【解决方案1】:

    由于 SpecialPlayer 对象应该在每一轮结束时替换 Player 对象,我认为不创建 SpecialPlayer 类来扩展 Player 会更合适。

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

    【讨论】:

    • 这是一个很好的处理方式,但我在考虑是否有其他方式来处理它,因为图像如果特殊播放器有很多数据和方法,可能会占用大量资源公羊?
    • 别担心。我无法想象额外数据占用的内存会太多。并且方法占用的内存量是“固定开销”;它不会随着创建的对象实例的数量而增加。
    【解决方案2】:

    我将不得不与其他人不同意,并告诉你这听起来你需要用SpecialPlayer 模块扩展你的Player instance。让我演示一下。假设你有一个玩家类:

    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 甚至都不起作用,因此您不会遇到普通玩家做他们不应该做的事情的错误。

    【讨论】:

    • 我真的很喜欢你的解决方案,这是 Ruby 的处理方式
    【解决方案3】:

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

    【讨论】:

    • 我用的是ruby,所以没有Interface,因为是动态语言
    • 今天我的课程讲师问了同样的问题,他也指了指装饰师。
    【解决方案4】:

    基本上,您希望Player 的行为根据它是否特殊而有所不同。在这类问题中,将变化的行为封装在接口 (IHandling) 中并让原始类依赖于该接口的实现是很有用的。在您的情况下,您可以让Player 将不同的行为委托给SpecialHandlingNormalHandling。您的正常处理无济于事。在每一轮之后,SpecialHandling 对象可以附加到另一个 Player

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

    【讨论】:

      猜你喜欢
      • 2014-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 1970-01-01
      • 2013-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多