【问题标题】:Ruby: how to use another object's getter to initialize a different object?Ruby:如何使用另一个对象的 getter 来初始化另一个对象?
【发布时间】:2017-01-16 20:15:47
【问题描述】:
class Car
  attr_reader :doors, :color

  def initialize(doors, color)
    @doors = doors
    @color = color
  end
end

class Motorcycle
  attr_reader :cc, :color

  def initialize(cc)
    @cc = cc
    @color = obtain_color
  end

  def obtain_color
    'orange' if my_car.color == 'green'
    'blue'
  end
end

class Vehicles
  attr_reader :my_car, :my_motorcycle

  def initialize
    @my_car = Car.new(4, 'green')
    @my_motorcycle = Motorcycle.new(950)
  end

  def display_colors
    puts "my_car color: #{my_car.color}"
    puts "my_motorcycle color: #{my_motorcycle.color}"
  end
end

my_vehicles = Vehicles.new
my_vehicles.display_colors

不出所料会产生以下错误:

in 'obtain_color': undefined local variable or method 'my_car' for #<Motorcycle:0x007fc1820690a0 @cc=950> (NameError)

为了解决这个问题,我像这样传入my_car 对象:

class Car
  attr_reader :doors, :color

  def initialize(doors, color)
    @doors = doors
    @color = color
  end
end

class Motorcycle
  attr_reader :cc, :color

  def initialize(cc, my_car)
    @cc = cc
    @color = obtain_color(my_car)
  end

  def obtain_color(my_car)
    'orange' if my_car.color == 'green'
    'blue'
  end
end

class Vehicles
  attr_reader :my_car, :my_motorcycle

  def initialize
    @my_car = Car.new(4, 'green')
    @my_motorcycle = Motorcycle.new(950, my_car)
  end

  def display_colors
    puts "my_car color: #{my_car.color}"
    puts "my_motorcycle color: #{my_motorcycle.color}"
  end
end

my_vehicles = Vehicles.new
my_vehicles.display_colors

问题:有没有办法从Motorcycle 的初始化中调用my_car.color 而不必传入my_car 对象?

【问题讨论】:

  • 不,你必须传入非类成员的数据。
  • 这可以使用 Forwardable 吗?

标签: ruby class object scope initialization


【解决方案1】:

简短的回答是否定的,因为摩托车如何知道要访问哪个 Car 实例?

这导致我们得到更长的答案,即:为什么摩托车要关心汽车是什么颜色?答案当然是不应该。

为了便于具体考虑,我们将Vehicles 类重命名为Garage。现在,如果我们有两个 Garage 实例:my_garageyour_garage。大概相同的“颜色规则”将适用于每个实例,但一个实例不会对另一个实例产生任何影响。如果你的车库里有一辆绿色汽车,我的车库里就不会有一辆橙色摩托车——除非我自己的车库里有一辆绿色汽车。

既然摩托车不应该关心汽车是什么颜色(或者即使汽车存在),那么我们如何让摩托车的颜色取决于汽车的颜色呢?我们把它留给车库:

class Motorcycle
  attr_reader :cc, :color

  def initialize(cc, color)
    @cc = cc
    @color = color
  end
end

class Garage
  attr_reader :my_car, :my_motorcycle

  def initialize
    @my_car = make_car
    @my_motorcycle = make_motorcycle
  end

  def make_car
    Car.new(4, "green")
  end

  def make_motorcycle
    if @my_car && @my_car.color == "green"
      color = "orange"
    else
      color = "blue"
    end

    Motorcycle.new(950, color)
  end

  def display_colors
    puts "my_car color: #{my_car.color}"
    puts "my_motorcycle color: #{my_motorcycle.color}"
  end
end

这有点做作,因为汽车的颜色是硬编码在 make_car 中的,所以我们也可以硬编码摩托车的颜色,但你明白了。

当对象像这样相互关联时,试图找出将逻辑放在哪里,结果证明,真的很难。你会做得更好,但如果你想省去很多麻烦,我高度推荐阅读Sandi Metz' Practical Object-Oriented Design in Ruby。它不仅是有史以来最好的 Ruby 书籍之一,也是有史以来最好的 OOP 书籍之一。

附:你的代码中有一个错误,在这里:

def obtain_color(my_car)
  'orange' if my_car.color == 'green'
  'blue'
end

此方法将始终返回"blue"。你可能是这个意思:

def obtain_color(my_car)
  return 'orange' if my_car.color == 'green'
  'blue'
end

【讨论】:

  • Motorcycle shouldn't care what color the Car is (or even if a Car exists) 的深层含义似乎是 OOP 的一个关键概念。我去看看书!
【解决方案2】:

为什么不从 Vehicles 类中设置摩托车的颜色。

您只需使颜色实例变量可以从其他类访问(通过使用 attr_accessor),然后添加一个方法来从 Vehicles 类中设置颜色。

class Car
  attr_reader :doors, :color

  def initialize(doors, color)
    @doors = doors
    @color = color
  end
end

class Motorcycle
  attr_reader :cc
  attr_accessor :color

  def initialize(cc)
    @cc = cc
    @color = nil
  end
end

class Vehicles
  attr_reader :my_car, :my_motorcycle

  def initialize
    @my_car = Car.new(4, 'green')
    @my_motorcycle = Motorcycle.new(950)
    set_motocycle_color
  end

  def set_motocycle_color
    my_motorcycle.color = (my_car.color == 'green') ? 'blue': 'orange'
  end

  def display_colors
    puts "my_car color: #{my_car.color}"
    puts "my_motorcycle color: #{my_motorcycle.color}"
  end
end

my_vehicles = Vehicles.new
my_vehicles.display_colors

# my_car color: green
# my_motorcycle color: blue

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 2016-05-30
    • 2016-12-18
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多