ruby 使用当前对象访问不同类的示例方法

mzillmmw  于 2023-08-04  发布在  Ruby
关注(0)|答案(2)|浏览(125)

在Sandi梅斯的《Practical Object-Oriented Design in Ruby》一书中:

class Gear
 attr_reader :chainring, :cog, :rim, :tire
 def initialize(chainring, cog, rim, tire)
  @chainring = chainring
  @cog = cog
  @rim = rim
  @tire = tire
 end

  def ratio
   chainring / cog.to_f
  end    
 def gear_inches
  ratio * Wheel.new(rim, tire).diameter #line number 11
 end
 # ...
end

class Wheel
 attr_reader :rim, :tire
 def initialize(rim, tire)
  @rim = rim
  @tire = tire
 end

 def diameter
  rim + (tire * 2)
 end
 # ...
 end

 Gear.new(52, 11, 26, 1.5).gear_inches

字符串
此引用的直接、明显的结果是,如果Wheel类的名称更改,则Gear的gear_inches方法也必须更改。从表面上看,这种依赖似乎无伤大雅。毕竟,如果一个Gear需要与一个Wheel对话,那么在某个地方,必须创建一个Wheel类的新示例。如果Gear本身知道Wheel类的名称,则如果Wheel的名称发生更改,则必须更改Gear中的代码。
事实上,处理名称更改是一个相对较小的问题。您可能有一个工具,允许您在项目中执行全局查找/替换。如果Wheel的名称更改为Wheely,查找和修复所有引用并不难。但是,如果Wheel类的名称发生更改,则必须更改上面的第11行,这是此代码的最小问题。还有一个更深层次的问题,远不那么明显,但破坏性要大得多。

**当Gear在其gear_inches方法中对Wheel的引用进行硬编码时,它明确声明它只愿意计算Wheel示例的齿轮英寸。Gear拒绝与任何其他类型的物体合作,即使该物体有直径并使用齿轮。

如果您的应用程序扩展到包括磁盘或圆柱体等对象,并且您需要知道使用它们的齿轮的齿轮英寸,则无法做到这一点。尽管磁盘和圆柱体自然有一个直径,但你永远无法计算它们的齿轮英寸,因为齿轮粘在轮子上。
我无法理解这一段被加粗了的文字。磁盘和圆柱体对象如何访问方法gear_inches,因为gear_inches是类Gear的示例方法。(向磁盘和圆柱体发送gear_inches消息)
请澄清。

vmdwslir

vmdwslir1#

磁盘和柱面对象如何访问方法gear_inches,因为gear_inches是类Gear的示例方法。
文本没有说磁盘或柱面应该调用gear_inches。恰恰相反:gear_inches需要一个 diameter 来计算它的返回值。现在,它从自己创建的Wheel示例中获取该直径。
然而,将Wheel.new(...)硬编码到该方法中会在GearWheel之间创建耦合。要放松这种耦合,您可以将wheel示例传递给Gear的初始化器。这正是Sandi在下一个例子中所展示的:
POODR,第41页:

class Gear
  attr_reader :chainring, :cog, :wheel
  def initialize(chainring, cog, wheel)
    @chainring = chainring
    @cog       = cog
    @wheel     = wheel
  end

  def gear_inches
    ratio * wheel.diameter
  end
# ...
end

# Gear expects a 'Duck' that knows 'diameter'
Gear.new(52, 11, Wheel.new(26, 1.5)).gear_inches

字符串

  • “a 'Duck' that knows 'diameter'”* 意味着wheel不必是一个实际的轮子(Wheel类的示例)。相反,它可以是响应diameter的任何对象,例如(假设的)圆盘或圆柱体。
j1dl9f46

j1dl9f462#

可以把它看作是一个更加假设的场景,因为它所描述的内容显然没有在您提供的示例中进行编码。
首先,请注意,在本例中,Wheel示例没有访问Gear类中的任何方法。相反,Gear是从Wheel示例访问方法。
其次,考虑Gear如何计算潜在不同类型的直径。现在使用Wheel.new(...)没有任何意义!你可以做的是,传递一个有diameter方法作为参数的对象,并在gear_inches内部调用该方法:

# One possible implementation
def gear_inches(object_with_diameter)
  ratio * object_with_diameter.diameter
end

字符串
现在,gear_inches依赖于传递的对象类型,而不是绑定到Wheel

相关问题