Ruby 私有实例变量,但有例外

发布于 2024-08-23 17:21:45 字数 859 浏览 14 评论 0原文

我正在用红宝石制作纸牌游戏。

我有 Game 类,它有一个 Player 对象数组。

 array_of_players = Array[
  Player.new("Ben"),
  Player.new("Adam"),
  Player.new("Peter"),
  Player.new("Fred"),
 ]
 my_game = Game.new(array_of_players)

 puts my_game.players[2].name #=> Peter

每个玩家也可以访问游戏,这样他们就可以访问游戏的重要部分,就像

self.game.last_card_dealt

每个玩家也有卡牌(Player.cards)一样,我想确保玩家不能访问彼此的卡牌。但是,游戏确实需要访问卡牌,所以我认为使用 private 不合适,而且玩家需要访问彼此的一些信息,所以我不认为我想要这样要么是私有...

基本上,我希望这些能够工作。

self.cards #where self is a Player object
self.players[0].cards #where self is the Game
self.game.players[0].name #where self is a Player object

这会失败:

self.hand.players[0].cards  #=> Nice try sucker! Cheating is for losers.

如何处理像这样的更复杂的权限? 谢谢。

I am making a card game in ruby.

I have the Game class, which has an array of Player objects.

 array_of_players = Array[
  Player.new("Ben"),
  Player.new("Adam"),
  Player.new("Peter"),
  Player.new("Fred"),
 ]
 my_game = Game.new(array_of_players)

 puts my_game.players[2].name #=> Peter

Each player also has access to the Game, so that they can access the important bits of the game like so

self.game.last_card_dealt

Each player also has cards (Player.cards), and I want to make sure that players can't access each other's cards. However, the Game does need access to the cards, so I don't think using private is appropriate, and the players need access to some of each other's information, so I don't think I want that to be private either...

Basically, I want these to work.

self.cards #where self is a Player object
self.players[0].cards #where self is the Game
self.game.players[0].name #where self is a Player object

And this to fail:

self.hand.players[0].cards  #=> Nice try sucker! Cheating is for losers.

How are more complex permissions like this handled?
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黎歌 2024-08-30 17:21:45

这比我的其他答案更实用,并使用 Game 对象作为游戏本身所有信息(玩家、卡牌等)的委托。请注意,您仍然必须相信呼叫者能够自行传递,但说真的,您在哪里划清界限呢?

class Player
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Cards
  attr_accessor :cards
end

class Game
  attr_reader :name, :players

  def initialize(players)
    @name = "Game Master"
    @hands = []
    @players = players.each do |p|
      puts "Added %s to game." % p.name
      @hands << {:player => p, :cards => Cards.new}
    end
  end

  def view_hand(player, caller)
    @hands.each do |hand|
      if hand[:player] == player
        if hand[:player] == caller or caller == self
          puts "%s: You can access all these cards: %s" % [caller.name, hand[:cards]]
        else
          # Do something to only display limited cards depending on this caller's view capabilities
          puts "%s: You can only access the cards I will let you see: %s" % [caller.name, hand[:cards]]
        end
      end
    end
  end

  def my_cards(player)
    @hands.each do |hand|
      puts "%s's cards: %s" % [player.name, hand[:cards]] if hand[:player] == player
    end
  end

end

g = Game.new([Player.new('Bob'), Player.new('Ben')])

puts "\nCalling each Player's cards as each Player:\n\n"
g.players.each do |gp|
  g.players.each do |p|
    g.view_hand(gp, p)
  end
end

puts "\nCalling each Player's cards as Game:\n\n"
g.players.each do |p|
  g.view_hand(p, g)
end

puts "\nEach Player calls for their own cards:\n\n"
g.players.each do |p|
  g.my_cards(p)
end

输出:

    Added Bob to game.
    Added Ben to game.

    Calling each Player's cards as each Player:

    Bob: You can access all these cards: #<Cards:0x100121c58>
    Ben: You can only access the cards I will let you see: #<Cards:0x100121c58>
    Bob: You can only access the cards I will let you see: #<Cards:0x100121bb8>
    Ben: You can access all these cards: #<Cards:0x100121bb8>

    Calling each Player's cards as Game:

    Game Master: You can access all these cards: #<Cards:0x100121c58>
    Game Master: You can access all these cards: #<Cards:0x100121bb8>

    Each Player calls for their own cards:

    Bob's cards: #<Cards:0x100121c58>
    Ben's cards: #<Cards:0x100121bb8>

This is more practical than my other answer, and uses the Game object as a delegate to all information in the game itself (Players, Cards, etc.). Note that you still have to trust the caller to pass themselves, but seriously where do you draw the line?

class Player
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Cards
  attr_accessor :cards
end

class Game
  attr_reader :name, :players

  def initialize(players)
    @name = "Game Master"
    @hands = []
    @players = players.each do |p|
      puts "Added %s to game." % p.name
      @hands << {:player => p, :cards => Cards.new}
    end
  end

  def view_hand(player, caller)
    @hands.each do |hand|
      if hand[:player] == player
        if hand[:player] == caller or caller == self
          puts "%s: You can access all these cards: %s" % [caller.name, hand[:cards]]
        else
          # Do something to only display limited cards depending on this caller's view capabilities
          puts "%s: You can only access the cards I will let you see: %s" % [caller.name, hand[:cards]]
        end
      end
    end
  end

  def my_cards(player)
    @hands.each do |hand|
      puts "%s's cards: %s" % [player.name, hand[:cards]] if hand[:player] == player
    end
  end

end

g = Game.new([Player.new('Bob'), Player.new('Ben')])

puts "\nCalling each Player's cards as each Player:\n\n"
g.players.each do |gp|
  g.players.each do |p|
    g.view_hand(gp, p)
  end
end

puts "\nCalling each Player's cards as Game:\n\n"
g.players.each do |p|
  g.view_hand(p, g)
end

puts "\nEach Player calls for their own cards:\n\n"
g.players.each do |p|
  g.my_cards(p)
end

The output:

    Added Bob to game.
    Added Ben to game.

    Calling each Player's cards as each Player:

    Bob: You can access all these cards: #<Cards:0x100121c58>
    Ben: You can only access the cards I will let you see: #<Cards:0x100121c58>
    Bob: You can only access the cards I will let you see: #<Cards:0x100121bb8>
    Ben: You can access all these cards: #<Cards:0x100121bb8>

    Calling each Player's cards as Game:

    Game Master: You can access all these cards: #<Cards:0x100121c58>
    Game Master: You can access all these cards: #<Cards:0x100121bb8>

    Each Player calls for their own cards:

    Bob's cards: #<Cards:0x100121c58>
    Ben's cards: #<Cards:0x100121bb8>
葬シ愛 2024-08-30 17:21:45

将 Game.player 保持私有以禁止玩家通过数组访问其他玩家。

例如,当 self 是玩家时,self.game.players[0].name 有点愚蠢。

也许您想要一个仅返回玩家姓名数组的公共 Game.player_names 方法?

最重要的是,您可以创建一个公共 Players.opponents 方法。

示例

Game.player_names

class Game
  # ...
  def player_names
    self.players.collect { |p| p.name }
  end

  private
  # private game methods
end

Player.opponents

class Player
  # ...
  def opponents(i=nil)
    return i.nil? ? self.game.player_names : self.game.player_names[i]
  end
end

Keep Game.player private to disallow players from accessing other players through the array.

e.g., When self is a player, self.game.players[0].name is kind of silly.

Perhaps you'd like a public Game.player_names method that just returns an array of player names?

On top of that, you could make a public Players.opponents method.

Examples

Game.player_names

class Game
  # ...
  def player_names
    self.players.collect { |p| p.name }
  end

  private
  # private game methods
end

Player.opponents

class Player
  # ...
  def opponents(i=nil)
    return i.nil? ? self.game.player_names : self.game.player_names[i]
  end
end
梦中的蝴蝶 2024-08-30 17:21:45

这玩起来很有趣。我不确定这是否是最好的答案,但它确实有效。关键是将调用对象传递给 Player.cards(obj),并检查它是否是 Player 本身或 Game 类型,两者都具有合法访问权限。

class Player
  attr_accessor :name, :game
  attr_writer :cards

  def initialize(name)
    @name = name
    @game = nil
    @cards = nil
  end

  def cards(caller)
    puts "%s cards called by %s." % [self, caller]
    if caller.kind_of?(Game) or caller == self
      puts "Here's your cards %s." % @cards
    else
      puts "Nice try sucker!  Cheating is for losers."
    end
  end
end

class Cards
  def initialize
    @cards = [1, 2, 3]
  end
end

class Game
  attr_reader :players

  def initialize(players)
    @players = players.each do |p|
      puts "Added %s to game." % p.name
      p.game = self
      p.cards = Cards.new
    end
  end
end

g = Game.new([Player.new('Bob'), Player.new('Ben')])

puts "\nCalling each Player's cards as each Player:\n\n"
g.players.each do |gp|
  g.players.each do |p|
    p.cards(gp)
  end
end

puts "\nCalling each Player's cards as Game:\n\n"
g.players.each do |p|
  p.cards(g)
end

和输出:

    Added Bob to game.
    Added Ben to game.

    Calling each Player's cards as each Player:

    #<Player:0x100122b30> cards called by #<Player:0x100122b30>.
    Here's your cards #<Cards:0x1001229c8>.
    #<Player:0x100122ae0> cards called by #<Player:0x100122b30>.
    Nice try sucker!  Cheating is for losers.
    #<Player:0x100122b30> cards called by #<Player:0x100122ae0>.
    Nice try sucker!  Cheating is for losers.
    #<Player:0x100122ae0> cards called by #<Player:0x100122ae0>.
    Here's your cards #<Cards:0x100122928>.

    Calling each Player's cards as Game:

    #<Player:0x100122b30> cards called by #<Game:0x100122ab8>.
    Here's your cards #<Cards:0x1001229c8>.
    #<Player:0x100122ae0> cards called by #<Game:0x100122ab8>.
    Here's your cards #<Cards:0x100122928>.

This was fun to play with. I'm not sure if this is the best possible answer, but it works. The key is to pass the calling object to Player.cards(obj), and check if it's either the Player itself, or of type Game, both of which have legal access.

class Player
  attr_accessor :name, :game
  attr_writer :cards

  def initialize(name)
    @name = name
    @game = nil
    @cards = nil
  end

  def cards(caller)
    puts "%s cards called by %s." % [self, caller]
    if caller.kind_of?(Game) or caller == self
      puts "Here's your cards %s." % @cards
    else
      puts "Nice try sucker!  Cheating is for losers."
    end
  end
end

class Cards
  def initialize
    @cards = [1, 2, 3]
  end
end

class Game
  attr_reader :players

  def initialize(players)
    @players = players.each do |p|
      puts "Added %s to game." % p.name
      p.game = self
      p.cards = Cards.new
    end
  end
end

g = Game.new([Player.new('Bob'), Player.new('Ben')])

puts "\nCalling each Player's cards as each Player:\n\n"
g.players.each do |gp|
  g.players.each do |p|
    p.cards(gp)
  end
end

puts "\nCalling each Player's cards as Game:\n\n"
g.players.each do |p|
  p.cards(g)
end

And the output:

    Added Bob to game.
    Added Ben to game.

    Calling each Player's cards as each Player:

    #<Player:0x100122b30> cards called by #<Player:0x100122b30>.
    Here's your cards #<Cards:0x1001229c8>.
    #<Player:0x100122ae0> cards called by #<Player:0x100122b30>.
    Nice try sucker!  Cheating is for losers.
    #<Player:0x100122b30> cards called by #<Player:0x100122ae0>.
    Nice try sucker!  Cheating is for losers.
    #<Player:0x100122ae0> cards called by #<Player:0x100122ae0>.
    Here's your cards #<Cards:0x100122928>.

    Calling each Player's cards as Game:

    #<Player:0x100122b30> cards called by #<Game:0x100122ab8>.
    Here's your cards #<Cards:0x1001229c8>.
    #<Player:0x100122ae0> cards called by #<Game:0x100122ab8>.
    Here's your cards #<Cards:0x100122928>.
各空 2024-08-30 17:21:45

感谢您的所有回复。

最后我想我可以给授权对象一个密钥,用于允许它访问方法的核心。

游戏对象具有@auth_object并将其设置为要访问其秘密方法的玩家对象,并且玩家秘密方法检查hand.auth_object是否为self,否则不执行任何操作。然后@auth_object被设置回nil。 @auth_object 有一个 attr_reader 但没有 writer。

那行得通。

Thanks for all your responses.

In the end I figured that I could give the authorised object a key which is used to allow it access to the meat of a method.

Game object has @auth_object and sets it to the player object it intends to access the secret methods of, and the player secret method checks if hand.auth_object is self, otherwise it does nothing. Then @auth_object is set back to nil. There is an attr_reader but no writer for @auth_object.

That works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文