Как получить доступ к справочному имени экземпляра класса? - PullRequest
0 голосов
/ 02 декабря 2018

Я совершенно новичок в Ruby и программировании в целом.

Чтобы инициализировать экземпляр класса, я бы сделал следующее:

ben_smith = Client.new("Ben Smith")

При необходимости я бы вызвал ссылку на экземпляр (не уверен, что «ссылка» является правильным термином):

ben_smith
=> #<Client:0x007fca2f630de8 @name="Ben Smith">

В настоящее время я изучаю объектные отношения Has-Many и написал метод, позволяющий экземпляру класса класса «Фрилансер» создавать другойэкземпляр класса класса "Клиент".

Проблема в том, что экземпляры Клиента созданы, но я не знаю, как получить к ним доступ независимо от экземпляра "freelancer_1".

class Client

  attr_accessor :name, :company, :freelancer

  def initialize(name, company)
    @name = name
    @company = company
  end

end

class Freelancer

  attr_accessor :name, :skill, :years_of_experience

  def initialize(name, skill, years_of_experience)
    @name = name
    @years_of_experience = years_of_experience
    @skill = skill
    @clients = []
  end

  def add_client_by_name(name, company)
    client = Client.new(name, company)
    @clients << client
    client.freelancer = self
  end

  def clients
    @clients
  end

end

Вотмой начальный код:

freelancer_1 = Freelancer.new("Bobby", "Plumber", 10)

freelancer_1.add_client_by_name("Howard Rose", "TNP")
freelancer_1.add_client_by_name("Antony Adel", "Realmless")
freelancer_1.add_client_by_name("Luke Tiller", "SKY")

Я бы хотел получить доступ к "клиентам" следующим образом:

luke_tiller.company

Но, похоже, нет ссылки на "luke_tiller".Я могу получить доступ к клиентам через freelancer_1:

freelancer_1.clients[2]

Я действительно не уверен

  1. , если можно назначить и сделать доступными именованные уникальные ссылки (client_1, client_2, client_3 и т. Д.), Используяметод add_client_by_name?
  2. Есть ли способ легко получить прямой доступ к клиентскому экземпляру?
  3. Почему экземпляры «ссылок» кажутся скрытыми для обоих приведенных примеров?Для первого примера я могу назвать ben_smith, но есть упоминание об этой ссылке, если мы назовем ben_smith.

Извинения за основные вопросы и мой довольно длинный пост.Заранее благодарю за оказанную помощь.

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Это своего рода «архитектурное» решение на тот случай, если в вопрос встроена проблема xy .

  • x не имеет структуры данных, которая хранит всех фрилансеров (и структуры данных, которая хранит всех клиентов).
  • y , проблема в вашем вопросе, вытекает из использования объектов для инкапсуляции данных (это хорошее использование объектов).Это затрудняет работу с данными в совокупности.Например, при написании кода, который ищет всех фрилансеров.

Структура данных для агрегатов

В структуре данных используются Array для @clients и @freelancers,Он обеспечивает add_freelancer и add_client, так что тип данных @clients и @freelancers может быть изменен на файл или базу данных без влияния на реализацию Client или Freelancer.

class MyDataStore
  attr_accessor :clients, :freelancers
  def initialize()
    @clients = Array.new
    @freelancers = Array.new
  end

  # hide @freelancers implementation details
  def add_freelancer(f)
    @freelancers.push(f)
  end

  # hide @clients implementation details
  def add_client(c)
    @clients.push(c)
  end

end

Модификация Freelancer.initialize

Для метода initialize теперь требуется объект MyDataStore (с именем 'db').Недавно созданный объект Freelancer добавляется в db во время инициализации.

class Freelancer
  attr_reader :name, :db, :skills, :clients

  def initialize(name,db) # db is a new argument
    @name = name
    @skills = Array.new
    @clients = Array.new
    db.add_freelancer(self) # the new Freelancer is added to db
  end

Аннотация над реализацией @skills и @clients

Пока мы думаем об этом, почему бы и нет?

  #abstract over implementation
  def add_skill(skill)
    @skills.push(skill)
  end

  def add_client(client)
    @clients.push(client)
  end

end

Пример среды

Простое применение кода.Вместо того, чтобы называть каждый объект самостоятельно, мы просто сохраняем объект.В большинстве случаев это то, что мы хотим при создании.

db = MyDataStore.new
Freelancer.new('a', db)
Freelancer.new('b', db)
Freelancer.new('c', db)
Freelancer.new('d', db)
Freelancer.new('a', db)

Интерактив Обратите внимание, что db.freelancers представляет собой совокупность объектов.Каждый объект уникально идентифицируется по хешу.Есть два разных фрилансера с именем 'a', и это не проблема (пока) .

Irb(main):10:0> db.freelancers
=> [#<Freelancer:0x00000001b1dd38 @clients=[], @name="a", @skills=[]>,
    #<Freelancer:0x00000001b1dc98 @clients=[], @name="b", @skills=[]>,
    #<Freelancer:0x00000001b1db30 @clients=[], @name="c", @skills=[]>,
    #<Freelancer:0x00000001b1d9f0 @clients=[], @name="d", @skills=[]>, 
    #<Freelancer:0x00000001b1c988 @clients=[], @name="a", @skills=[]>]

Получение фрилансера по имени

Внимание: этокод зависит от деталей реализации. Это может быть скрыто

irb(main):907:0> db.freelancers.select {|f| f.name == 'a'}
=> [#<Freelancer:0x00000001b1dd38 @clients=[], @name="a", @skills=[]>,
    #<Freelancer:0x00000001b1c988 @clients=[], @name="a", @skills=[]>]

Добавление навыка и клиента

Предупреждение: этот код опирается на детали реализации. Этотакже предполагается, что класс Client был реализован.

# add @skill 'Ruby' to freelancer named 'b'
irb(main):10:0> db.freelancers.select {|f| f.name == 'b'}[0].add_skill('Ruby')
=> ["Ruby"]

# check freelancer named 'b' has skill 'Ruby'
irb(main):11:0> db.freelancers.select {|f| f.name == 'b'}
=> [#<Freelancer:0x00000001f16e58 @clients=[], @name="b", @skills=["Ruby"]>]

# uses '\' to span two lines for readability here on stackoverflow
irb(main):195:0> db.freelancers.select {|f| f.name == 'b'} \ 
                 [0].add_client(Client.new('Best Client', db))
=> [#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]

#check that 'Best Client' has been added to db.clients
irb(main):196:0> db.clients
=> [#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]

#check that 'Best Client' has been added to freelancer named 'b'
irb(main):197:0> db.freelancers.select {|f| f.name == 'b'} [0]
=> #<Freelancer:0x00000001e096f0 @name="b", 
                                 @skills=[], 
                                 @clients=[#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]>

Обсуждение

Стоит подчеркнуть, мы всегда храним и передаем объекты и избегаем присвоения объектовпеременные, когда это возможно.Когда невозможно избежать назначения объекта переменной, мы стараемся сделать это временно в блоке, например {|f| f.name == 'b'}.

  • . Также важно подтвердить хранение данных.и поиск труден. И здесь мы проектируем наше собственное объектно-ориентированное хранилище данных .Существует масштаб, в котором это имеет смысл.
  • Существуют приложения, в которых поддержание необходимой целостности данных с использованием внешней базы данных (SQLite, mySQL, Postgres) имеет больше смысла.
0 голосов
/ 02 декабря 2018

Вместо доступа на основе индекса вы можете добавить новый метод в класс Freelancer, например:

class Freelancer
  def find_client_by_name(name)
    @clients.find { |client| client.name == name }
  end
end

Теперь вы можете сделать:

luke_tiller = freelancer_1.find_client_by_name('Luke Tiller')
puts luke_tiller.company
# SKY
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...