如何应用Demeter定律?

时间:2012-01-21 02:14:57

标签: ruby-on-rails refactoring law-of-demeter

我有一个公认的难看的查询,要找到与当前角色相关的特定角色。该行产生正确的结果:

@person_event_role.event_role.event.event_roles.
  joins(:mission_role).where(:mission_roles => {:title => 'Boss'}).
  first.person_event_roles.first.person

(您可以推断多个呼叫中的关联)

获取此信息的唯一方法需要大量数据库结构的知识,但要删除耦合...这需要在该链的每个步骤中填充一堆辅助函数以返回需要的信息...

1 个答案:

答案 0 :(得分:1)

我认为这里要做的是在适当的时候创建帮助函数。我不清楚你的关联链的起点是什么,但我可能会为它分配一个返回#event的方法event_role.event。从那里开始,event有一个#boss_role,或者任何语义上有意义的,并且该方法是

event_roles.joins(:mission_role).where(:mission_roles => {:title => 'Boss'}).first 

最后,同样在Event模型上,有一个#boss方法,

boss_roles.first.person_event_roles.first.person

因此,原始查询变为

@person_event_role.event.boss

链条的每一条腿都是独立且易于理解的,并且它不需要链条的开头就其结尾而言是无所不知的。我并不完全理解这些关联的完整范围,但我很确定只要将其分解为三种或四种模型方法,就能让您清楚地阅读和分离您正在寻找的关注点。你甚至可以进一步分解它以便于阅读,但这会成为一种风格问题。

希望有所帮助!

以下是原始提问者

我想我遵循了这个建议并最终得到了:

@person_event_role.get_related_event_roles_for('Boss').first.filled_by.first

#person_event_role:
def get_related_event_roles_for(role)
  event.event_roles_for(role)
end

def event
 event_role.event
end

#event:
def event_roles_for(role)
  event_roles.for_role(role)
end

#event_role:
scope :for_role, lambda {|role| joins(:mission_role).where(:mission_roles => {:title => role})}
def filled_by
  person_event_roles.collect {|per| per.person}
end