use*_*382 3 ruby oop delegates ruby-on-rails
我目前正在学习delegate
和Demeter法,我似乎无法找到一个很好的例子,其中使用delegate
实际上甚至是有用的.
我想找一个与我的项目相关的例子,因为我必须做一个演示.我发现可能违反Demeter法则的唯一代码行如下:
@game.promotions.find_by_promo_type("cross")
该模型Game
has_many
Promotions
正在跨越另一个模型,以find
基于促销属性执行呼叫promo_type
.根据我的理解,这违反了得墨忒耳法,我应该通过使用委托来解决这个问题:
class Game < ActiveRecord::Base
has_many :promotions
delegate :find_by_promo_type, :to => :promotion
end
Run Code Online (Sandbox Code Playgroud)
你能给我一个例子吗?除了"得墨忒耳法则如此说明"之外,它实际上是有用的.
我能想到的唯一的事情,是出于某种原因我想改变的名称promotions
来promos
,那么解决将是有益的,因为我只需要进行以下变化,:find_by_promo_type
将仍然正常工作Game
class Game < ActiveRecord::Base
has_many :promos
delegate :find_by_promo_type, :to => :promos
end
Run Code Online (Sandbox Code Playgroud)
唯一的问题是,我认为这个论点是有缺陷的.如果我要更改模型名称,我还必须在许多其他地方重构代码,甚至不破坏Demeter法则.很难相信这就是德米特的所有法则都可以在这个例子中完成的.
有人可以帮我理解这一点.
使用delegate
可以具有抽象实现某些事情的实现的优点.在您的例子,它与其说是允许您更改的名称promotions
来promos
.这是关于你对"外部世界",或者你的对象的API所暴露的内容非常有目的性.Game
与之交谈的对象不需要知道您正在使用另一个ActiveRecord模型来检索关联的对象Promotions
.它可以添加不必要的耦合.
所有LoD违规都不一定是坏事,但它们可以作为代码气味,你应该在看到它们时暂停.您需要平衡移除LoD违规的成本与潜在成本以及更改对象API的可能性.
我强烈推荐阅读Ruby中实用面向对象设计的第4章:Sandi Metz的敏捷入门.它很好地涵盖了这个主题,并指出:"使用委托隐藏紧密耦合与解耦代码不同."
在您的情况下,您可能希望从调用者的角度更多地考虑它以及它应该发送给什么消息Game
.也许它应该只是调用Game.cross_promotions
而不是Game
在另一个对象上调用方法,无论它是否被委托.