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
问题:有没有办法在my_car.color
的初始化内调用Motorcycle
而无需传入my_car
对象?
答案 0 :(得分:2)
简短的回答是否定的,因为摩托车如何知道要访问哪个Car实例?
这引出了我们更长的答案,即:为什么摩托车应该关注汽车的颜色?答案当然是,它不应该。
为了让您更容易用具体的术语思考,让我们将Vehicles
类重命名为Garage
。现在,如果我们有两个Garage实例,那该怎么办:my_garage
和your_garage
。大概是相同的颜色规则&#34;将适用于每个实例,但一个实例不会对另一个实例产生任何影响。如果你的车库里有一辆绿色的汽车,我的矿车里面没有橙色摩托车 - 除非我在自己的车库里有一辆绿色的汽车。
由于摩托车不应该关注汽车的颜色(或者即使汽车存在),我们如何使摩托车的颜色依赖于汽车的颜色呢?我们把它留给车库:
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
这有点人为,因为Car的颜色在make_car
中是硬编码的,所以我们也可以硬编码摩托车的颜色,但你明白了。
当对象相互关联时,试图找出逻辑放置的位置,事实证明,真的很难。你会变得更好,但是如果你想为自己节省很多头脑,我高度建议阅读Sandi Metz' Practical Object-Oriented Design in Ruby。它不仅是有史以来最好的Ruby书籍之一,也是有史以来最好的OOP书籍之一。
P.S。你的代码中有一个错误,在这里:
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
答案 1 :(得分:1)
为什么不从Vehicle类中设置摩托车的颜色。
您只需要从其他类(通过使用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