当前位置:  开发笔记 > 后端 > 正文

Ruby mixins正在寻找最佳实践

如何解决《Rubymixins正在寻找最佳实践》经验,为你挑选了1个好方法。

我正在编写Ruby Gem,我有配置Connection模块Faraday

module Example
  module Connection
    private

    def connection
      Faraday.new(url: 'http://localhost:3000/api') do |conn|
        conn.request  :url_encoded             # form-encode POST params
        conn.response :logger                  # log requests to STDOUT
        conn.adapter  Faraday.default_adapter  # make requests with Net::HTTP
        conn.use      Faraday::Response::ParseJson
        conn.use      FaradayMiddleware::RaiseHttpException
      end
    end
  end
end

发出API请求的第二个模块如下所示:

module Example
  module Request
    include Connection

    def get(uri)
      connection.get(uri).body
    end

    def post(url, attributes)
      response = connection.post(url) do |request|
        request.body = attributes.to_json
      end
    end

    def self.extended(base)
      base.include(InstanceMethods)
    end

    module InstanceMethods
      include Connection

      def put(url, attributes)
        response = connection.put(url) do |request|
          request.body = attributes.to_json
        end
      end
    end
  end
end

Cusomer我使用的类Request看起来像这样:

module Example
  class Customer
    extend  Request

    attr_accessor :id, :name, :age

    def initialize(attrs)
      attrs.each do |key, value|
        instance_variable_set("@#{key}", value)
      end
    end

    def self.all
      customers = get('v1/customer')
      customers.map { |cust| new cust }
    end

    def save
      params = {
        id:   self.id,
        age:  self.age
        name: self.name,
      }

      put("v1/customers/#{self.id}", params)
    end
  end
end

所以在这里你看到Customer#all类方法我正在调用Request#get 方法,因为我扩展RequestCustomer.然后我在Request模块中使用self.extended方法在课堂上Request#put可用Customer,所以我有一个问题就是使用这样的mixins这个好方法,或者你有什么建议吗?



1> Josh Bodah..:

Mixins是一个奇怪的野兽.最佳做法取决于您与谁交谈.就重用而言,你已经通过mixins实现了这一点,并且你可以很好地分离关注点.

但是,mixins是一种继承形式(你可以看看#ancestors).我会挑战你说你不应该在这里使用继承,因为Customer它没有"is-a"关系Connection.我建议你改用合成(例如传入Connection/Request),因为在这种情况下对我来说更有意义并且具有更强的封装性.

写混入其中一个原则是使一切在"-able"结束了,所以你有Enumerable,Sortable,Runnable,Callable,等.在这个意义上,混入是提供某种形式的被依赖一个非常特殊的接口上佣工(通用扩展如Enumerable取决于要实施的类#each).

您也可以使用mixins来解决交叉问题.例如,我们过去在后台作业中使用了mixins,因此我们可以添加日志记录,而无需触及类的源代码.在这种情况下,如果一个新工作想要记录,那么他们只是混合与框架耦合的关注点并将正确地注入自己.

我的一般经验法则是,如果您不需要,请不要使用它们.在大多数情况下,他们使代码的理解变得更加复杂

编辑:添加组合的示例.为了维护上面的接口,你需要有某种全局连接状态,所以它可能没有意义.这是使用合成的替代方案

class CustomerConnection
  # CustomerConnection is composed of a Connection and retains isolation
  # of responsibilities. It also uses constructor injection (e.g. takes
  # its dependencies in the constructor) which means easy testing.
  def initialize(connection)
    @connection = connection
  end

  def all_customers
    @connection.get('v1/customers').map { |res| Customer.new(res) }
  end
end

connection = Connection.new
CustomerConnection.new(connection).all_customers

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有