Хранить коллекцию объектов Ruby - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь сохранить коллекцию объектов в другом объекте.Я выполнил задание на кодирование, которое выглядит следующим образом.

Сначала единственный объект:

class Account
  attr_reader :user_name, :credit, :debit

  def initialize(user_name)
    @user_name = user_name
    @credit = 0
    @debit = 0
  end
end

Следующий набор:

class AccountsCollection
  attr_reader :accounts

  def initialize
    @accounts = []
  end

  def add_new_account(user)
    accounts << Account.new(user)
  end

  ...
end

Вот как я его использую:

accounts = AccountsCollection.new
# => #<AccountsCollection:0x00007fc76ba70b18 @accounts=[]>
accounts.add_new_account('A')
accounts.add_new_account('B')
accounts.add_new_account('C')
accounts.accounts
# =>[
#     #<Account:0x00007fc76b933890 @user_name="A">,
#     #<Account:0x00007fc76bc76d68 @user_name="B">,
#     #<Account:0x00007fc76c88c2d8 @user_name="C">
#   ]

Я хотел использовать это так:

class Display
  attr_reader :accounts

  def initialize(accounts)
    @accounts = accounts
  end

  def display_inline
    accounts.each do |account|
      #do something
  end
  ...
end

Display.new(accounts.accounts).display_inline

Но мне нужно позвонить accounts.accounts, чтобы получить список объектов аккаунта.Это странно?Может кто-нибудь показать мне, как я могу сделать это лучше?

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Запах кода, IMO, в вашем коде просто в том, что это коллекция, но я не могу относиться к ней как к коллекции.Например, если бы я хотел, чтобы все учетные записи имели более 10 кредитов, мне пришлось бы извлечь массив учетных записей из коллекции, чтобы сделать это:

accounts.accounts.select { |account| account.credit > 10 }

, тогда как на самом деле вы хотитечтобы иметь возможность просто запросить у нее коллекцию:

accounts.select { |account| account.credit > 10 }

Чтобы ваша коллекция выглядела как коллекция, вам нужно включить Enumerable, что требует реализации each method:

class AccountsCollection
  include Enumerable

  def initialize
    @accounts = []
  end

  def add(user_name)
    @accounts << Account.new(user_name)

    self # return self because that's more in-line with other collections
  end

  def each
    return to_enum(__method__) { @accounts.size } unless block_given?

    @accounts.each { |account| yield account }
  end
end

и теперь вы можете обрабатывать свою коллекцию как другие коллекции в ruby:

accounts = AccountsCollection.new
accounts.add('A').add('B').add('C')

accounts.each.with_index do |account, index|
  # I changed the attr_reader in Account to attr_accessor just to illustrate
  account.credit = index * 10
end

accounts.select { |account| account.credit > 10 }
# => [#<Account:0x00007fe50d894208 @user_name="C", @credit=20, @debit=0>]

, и если вы хотите, чтобы она была массивом, вы автоматическитакже есть метод to_a:

accounts.to_a
# => [#<Account:0x00007f879a094538 @user_name="A", @credit=0, @debit=0>,
#     #<Account:0x00007f879a094308 @user_name="B", @credit=10, @debit=0>,
#     #<Account:0x00007f879a0968b0 @user_name="C", @credit=20, @debit=0>]

это (по умолчанию) создаст новый массив, пройдя через метод each, поэтому массив не будет изменен напрямую (хотя содержимое все ещеможет быть)

accounts.to_a[1].debit = 15
accounts.to_a << 'not an account'

accounts.to_a
# => [#<Account:0x00007fb51c08a9c0 @user_name="A", @credit=0, @debit=0>,
#     #<Account:0x00007fb51c08a6a0 @user_name="B", @credit=10, @debit=15>,
#     #<Account:0x00007fb51c08a588 @user_name="C", @credit=20, @debit=0>]

Вы всегда можете заменить любой метод Enumerable на лучшую, персонализированную реализацию, если хотите:

def to_a
  @accounts.dup
end

Теперь все начинает ощущаться и пахнутьнамного лучше, с минимальнымrk и другие, пытающиеся использовать ваш AccountsCollection, будут очень рады, что у них есть доступ ко всем методам поиска и обхода, к которым они привыкли.

0 голосов
/ 06 июня 2018

На самом деле это выглядит хорошо для меня, кроме имен, выглядящих неловко.Если бы это был я, у меня были бы такие имена, чтобы он выглядел хорошо при использовании.

class AccountsCollection
  def initialize
    @accounts = []
  end

  def add(user)
    accounts << Account.new(user)
  end

  def to_a
    @accounts
  end
end

Тогда ваш код выглядел бы как

accounts = AccountsCollection.new
 => #<AccountsCollection:0x00007fc76ba70b18 @accounts=[]>

accounts.add('A')
accounts.add('B')
accounts.add('C')

accounts.to_a
 =>[
   #<Account:0x00007fc76b933890 @user_name="A">,
   #<Account:0x00007fc76bc76d68 @user_name="B">,
   #<Account:0x00007fc76c88c2d8 @user_name="C">
 ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...