• 讲一下个人理解 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)进行设计和编码。

    以上仅作参考。