Rails为什么要使用委托?

时间:2013-10-17 02:17:58

标签: ruby-on-rails ruby oop delegates

我目前正在了解delegate和得墨忒耳法,我似乎找不到使用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

你能给我一个例子,除了“得墨忒耳法则如此”之外,这实际上是有用的。

我唯一能想到的是,出于某种原因,我想将promotions的名称更改为promos,然后解决方案将非常有用,因为我只需要进行以下更改并且:find_by_promo_type仍适用于Game

class Game < ActiveRecord::Base
   has_many :promos

   delegate :find_by_promo_type, :to => :promos
end

唯一的问题是,我认为这种说法是有缺陷的。如果我要更改模型名称,我还必须在许多其他地方重构代码,甚至不破坏Demeter法则。很难相信这就是德米特法则可以在这个例子中完成的所有内容。

有人可以帮助我理解这一点。

1 个答案:

答案 0 :(得分:5)

使用delegate可以提取抽象实现方式的实现。在您的示例中,允许您将promotions的名称更改为promos并非如此。这是关于你对“外部世界”,或者你的对象的API所暴露的内容非常有目的性。与Game对话的对象不需要知道您正在使用另一个ActiveRecord模型来检索关联的Promotions。它可以添加不必要的耦合。

所有LoD违规行为都不一定是坏事,但它们可以作为代码气味,你应该在看到它们时暂停。您需要平衡移除LoD违规的成本与潜在成本以及更改对象API的可能性。

我强烈推荐阅读Ruby中实用面向对象设计的第4章:Sandi Metz的敏捷入门。它很好地涵盖了这个主题并指出: “使用委托隐藏紧密耦合与解耦代码不同。”

在您的情况下,您可能希望从调用方的角度更多地考虑它以及它应该向Game发送什么消息。也许它应该只是调用Game.cross_promotions而不是进入Game来调用另一个对象上的方法,无论它是否被委派。