如何访问类实例的引用名称?

时间:2018-12-01 23:15:19

标签: ruby object

我是Ruby和程序设计的新手。

要初始化类实例,我将执行以下操作:

ben_smith = Client.new("Ben Smith")

根据需要,我将调用实例引用(不确定“引用”是否正确):

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

我目前正在学习Has-Many对象关系,并编写了一种方法,以允许“ Freelancer”类的类实例创建“ Client”类的另一个类实例。

问题在于创建了Client实例,但我不知道如何独立于“ 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. 是否可以使用add_client_by_name方法分配并提供命名的唯一引用(client_1,client_2,client_3等)?
  2. 有没有一种方法可以轻松地直接访问客户端实例?
  3. 为什么对于两个示例都似乎隐藏了实例“引用”?对于第一个示例,我可以调用ben_smith,但是如果我们调用ben_smith,则会提及此参考。

道歉的基本问题和我相当长的帖子。 预先感谢您提供的任何帮助。

2 个答案:

答案 0 :(得分:1)

您可以在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

答案 1 :(得分:0)

这是一种“建筑”解决方案,以防万一问题中嵌入了xy Problem

  • x 没有存储所有自由职业者的数据结构(和存储所有客户端的数据结构)。
  • 问题
  • y 是使用对象封装数据(这是对对象的一种很好的使用)。这使得很难处理汇总数据。例如,编写搜索 all 自由职业者的代码。

聚合的数据结构

数据结构对Array@clients使用@freelancers。它提供add_freelanceradd_client,以便可以将@clients@freelancers的数据类型更改为文件或数据库,而不会影响Client或{ {1}}。

Freelancer

Freelancer.initialize的修改

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 方法现在需要一个initialize对象(名为“ db”)。新创建的MyDataStore对象在初始化期间被添加到Freelancer

db

@skills和@clients实现的摘要

我们正在考虑,为什么不呢?

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

示例环境

代码的简单应用。不用自己命名每个对象,我们只存储对象。在大多数情况下,这就是我们想要的创作。

  #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) 是对象的集合。每个对象都由其哈希唯一标识。有两个名为“ a”的自由职业者,(尚未)这不是问题。

db.freelancers

通过名称获取自由职业者

警告:此代码取决于实现细节。这可能是隐藏的

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=[]>]>

  • 重要的是要认识到数据存储和检索非常困难。。在这里,我们正在设计自己的面向对象的数据存储。有一个合理的规模。
  • 在某些应用程序中,使用外部数据库(SQLite,mySQL,Postgres)维护必要的数据完整性更加有意义。