【发布时间】:2016-07-12 02:09:25
【问题描述】:
我有一个 PORO (Plain Old Ruby Object) 来处理一些业务逻辑。它接收一个ActiveRecord 对象并对其进行分类。为简单起见,以以下为例:
class Classificator
STATES = {
1 => "Positive",
2 => "Neutral",
3 => "Negative"
}
def initializer(item)
@item = item
end
def name
STATES.fetch(state_id)
end
private
def state_id
return 1 if @item.value > 0
return 2 if @item.value == 0
return 3 if @item.value < 0
end
end
但是,我还想根据这些state_id“虚拟属性”对对象进行分组查询。我目前正在通过在 SQL 查询中创建此属性并在 GROUP BY 语句中使用它来处理这个问题。看例子:
class Classificator::Query
SQL_CONDITIONS = {
1 => "items.value > 0",
2 => "items.value = 0",
3 => "items.value < 0"
}
def initialize(relation = Item.all)
@relation = relation
end
def count
@relation.select(group_conditions).group('state_id').count
end
private
def group_conditions
'CASE ' + SQL_CONDITIONS.map do |k, v|
'WHEN ' + v.to_s + " THEN " + k.to_s
end.join(' ') + " END AS state_id"
end
end
这样,我可以把这个业务逻辑放到 SQL 中,并以一种非常有效的方式进行这种查询。
问题是:我有重复的业务逻辑。它存在于“ruby”代码中,用于对单个对象进行分类,也存在于“SQL”中,用于对数据库级别的对象集合进行分类。
这是一种不好的做法吗?有没有办法避免这种情况?我实际上能够做到这一点,执行以下操作:
item = Item.find(4)
items.select(group_conditions).where(id: item.id).select('state_id')
但是通过这样做,我失去了对未保存在数据库中的对象进行分类的能力。另一种方法是使用迭代器在 ruby 中对每个对象进行分类,但这样我会失去数据库性能。
如果我需要这两种情况中最好的一种,保留重复的业务逻辑似乎是不可避免的。但我只想确定这一点。 :)
谢谢!
【问题讨论】:
标签: ruby-on-rails ruby oop design-patterns architecture