讲一下个人理解 Repository 的用法,不一定是 Lotus 最好的用法。
逻辑上以 Repository 和模型一对一(不一定是一张表),多个 Repository 支持一个 Service 操作的方式区分代码职责。比如
Order.where(id: [1,2]).includes(order_items: :product)
拆分为
class OrderService
attr_reader :order_repository
attr_reader :order_item_repository
attr_reader :product_repository
def initialize
@order_repository = nil
@order_item_repository = nil
@product_repository = nil
end
def list_with_item_and_product(id_list)
orders = @order_repository.list(id_list)
# fill orders with items and products
# from order_item_repository and product repository
end
end
controllers 不处理类似代码,因为不利于代码复用。 第二个场景也是类似的方式。
class ConversationService
attr_reader :reply_repository
attr_reader :attachment_repository
def initialize
@reply_repository = nil
@attachment_repository = nil
end
def save_reply(message, attachments)
# validate parameters
# begin transaction
reply = Reply.new
reply.message = message
@reply_repository.save(reply)
# create and save attachments
# end transaction
reply
end
end
遇到类似的代码职责问题可以通过建立一个中间层来解决(但是记住不能建太多),这里实际上是一个业务逻辑层。
Rails 自身在设计的时候有意忽视了这点(因为目标客户的原因),把 Repository 和模型合并(后果就是在没有数据库的时候你无法测试),预期 Controller 中不会有太复杂逻辑,采用了一些不是最佳的代码复用手段。理解这点后,你就可以不拘泥于 Rails 的设计而按照常规的软件架构(不仅仅是 MVC)进行设计和编码。
以上仅作参考。