rubyists 是否引用 mixins 中的访问器?
从 mixin 方法中引用扩展对象上的访问器是否被认为是不好的做法?一个简单的例子:
module WindInstrument
def play
mouthpiece.blow #requires a mouthpiece
end
end
class Saxophone
attr_reader :mouthpiece
def initialize
@mouthpiece = Mouthpiece.new
end
include WindInstrument
end
Saxophone.new.play
在这种情况下,我实际上只是将吹嘴的需求直接转移到 WindInstrument 模块,但是在更复杂的场景中,访问器驻留在扩展对象上确实有意义吗?这只是一个不恰当的关注点分离问题吗?
Mixin 对于添加不需要了解扩展对象状态的封装行为很有用。事实上,我的直觉告诉我,mixin 不应该了解任何状态。如果需要了解状态,我通常会选择以下两种选择之一:
将状态放入类中,并通过组合添加它,而不是通过继承层次结构。 我的问题我知道 rubyists 正在创建访问状态的 mixin,这使得(对我来说)设计不太直观,但更具可读性。
将吹嘴作为参数传递给模块。即使我也可以看出,这似乎使设计变得混乱,并且在 ruby 世界观中感觉像是一种令人厌恶的行为。
这段代码会打扰其他人吗?我知道有很多聪明的人使用 ruby,所以我认为问题是我的。我缺少什么?我需要冷静一下吗? 你会做什么?
Is it considered bad practice to reference accessors on the extended object from within a mixin method? A simplistic example:
module WindInstrument
def play
mouthpiece.blow #requires a mouthpiece
end
end
class Saxophone
attr_reader :mouthpiece
def initialize
@mouthpiece = Mouthpiece.new
end
include WindInstrument
end
Saxophone.new.play
In this case, I would actually just move the requirement for a mouthpiece directly to the WindInstrument module, but what about in a more complex scenario, where it really makes sense for the accessor to live on the extended object? Is this just an issue of an inappropriate separation of concerns?
Mixins feel useful for adding encapsulated behavior that doesn't require knowledge of the extended object's state. In fact, my gut tells me that a mixin shouldn't have knowledge of any state, whatsoever. If it needs knowledge of state, I would typically fall back to one of two choices:
Put the state in a class, and add it through composition, instead of through the inheritance hierarchy. My issue with this is that I know rubyists out there are creating mixins that access state, which makes for more readable, if less intuitive (to me) design.
Pass the mouthpiece as a parameter to the module. Even I can tell that this seems to muddy the design, and feels like an abomination in the ruby worldview.
Does this code bother anyone else? I know there are a lot of smart people using ruby out there, so I assume the problem is mine. What am I missing? Do I just need to chill out? What would you do?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这与猴子修补中的相同:可以这样做,但是您必须首先确保没有其他选择(即您不能使用您的界面修改类),其次,您必须非常明确说明它(确保文档、注释和接口提到我们的方法是必需的并将被调用),如果不是,则抛出有用的错误消息
I think it's the same as in monkey-patching: it's ok to do it, but you have to make sure that there are no alternatives first (ie. You can't modify the classes using your interface) and second, you must be very explicit about it (make sure that the docs, the comments and the interface mention that this our that method is required and will be invoked) and throw a useful error message if it isn't
Ruby 的访问器是接口,而不是实现。
例如,如果您调用
person.height_in_feet=
,您不知道高度实际以什么单位实现为实例变量。它可以是米、英尺或肘。使用访问器的 mixins 的一个现实示例是
Enumerable
模块。尽管我没有将此模块包含在我创建的任何类中,但我对它的作用很满意。它为您提供了方便的方法,例如map
和each_with_index
,同时保持 DRY - 对于您使用“mixee”的所有方法访问的对象只有一种实现,对于任何使用Enumerable
的对象,map
的作用只有一个定义。Ruby's accessors are interfaces, not implementation.
For example, if you call
person.height_in_feet=
, you don't know what units the height is actually implemented in as an instance variable. It could be metres, feet, or cubits.One real-life example of mixins using an accessor is the
Enumerable
module. Although I don't include this module in any classes I create, I'm happy with what it does. It gives you convenient methods likemap
andeach_with_index
, while staying DRY - there's only one implementation of what objects you'd access with all of the methods of the "mixee", and there's only one definition of whatmap
does, for any object that usesEnumerable
.