在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消息)
请澄清。
2条答案
按热度按时间vmdwslir1#
磁盘和柱面对象如何访问方法
gear_inches
,因为gear_inches
是类Gear
的示例方法。文本没有说磁盘或柱面应该调用
gear_inches
。恰恰相反:gear_inches
需要一个 diameter 来计算它的返回值。现在,它从自己创建的Wheel
示例中获取该直径。然而,将
Wheel.new(...)
硬编码到该方法中会在Gear
和Wheel
之间创建耦合。要放松这种耦合,您可以将wheel示例传递给Gear
的初始化器。这正是Sandi在下一个例子中所展示的:POODR,第41页:
字符串
wheel
不必是一个实际的轮子(Wheel
类的示例)。相反,它可以是响应diameter
的任何对象,例如(假设的)圆盘或圆柱体。j1dl9f462#
可以把它看作是一个更加假设的场景,因为它所描述的内容显然没有在您提供的示例中进行编码。
首先,请注意,在本例中,
Wheel
示例没有访问Gear
类中的任何方法。相反,Gear
是从Wheel
示例访问方法。其次,考虑
Gear
如何计算潜在不同类型的直径。现在使用Wheel.new(...)
没有任何意义!你可以做的是,传递一个有diameter
方法作为参数的对象,并在gear_inches
内部调用该方法:字符串
现在,
gear_inches
依赖于传递的对象类型,而不是绑定到Wheel
。