冒险村30 - Handle API response with value objects

30 - Handle API response with value objects

本篇将介绍撰写 Rails 的过程中整个重构的过程,比较偏向一个方向,以一个简单的例子为例,假设我们请求 API 获取 Active 的 User 列表:

以下的程序是一个很常见的方法,但这段程序码中,不只打 Api + parser + 过滤 active user,这样的方式并没有办法让程序码只负责一件事情。

  response = Request.call('some_url')
  parsed_response = JSON.parse(response)

  eligible_users = []

  parsed_response['people'].each do |person|
    if person['active'] == true
      eligible_users << {
        name: "#{person['firstName']} #{person['lastName']}",
        email: person['emailAddress']
      }
    end
  end

  eligible_users

The parser for the people

Parser 的责任在负责接收并提供方法来 return User

  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = []

  parser.people.each do |person|
    if person['active'] == true
      eligible_users << {
        name: "#{person['firstName']} #{person['lastName']}",
        email: person['emailAddress']
      }
    end
  end

  eligible_users

Value object for a person

我们需要一个 pure ruby object 来处理 person

  class Person
    def initialize(attributes)
      @attributes = attributes
    end

    def active?
      @attributes['active']
    end

    def email
      @attributes['emailAddress']
    end

    def name
      "#{@attributes['firstName']} #{@attributes['lastName']}"
    end
  end

有了上述的 Person Object 我们的 Parser 可以再来进行修改

  class PeopleParser
    def initialize(raw_response)
      @raw_response = raw_response
    end

    def people
      @parsed_json['people'].map { |attributes| Person.new(attributes) }
    end

    private

    def parsed_json
      @parsed_json ||= JSON.parse(@raw_response)
    end
  end
  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = []

  parser.people.each do |person|
    if person.active?
      eligible_users << {
        name: person.name,
        email: person.email
      }
    end
  end

  eligible_users

再来继续重构:

Let person behave like a hash

接下来我们要命名一个 to_h 来组成 name + email 的 hash

  class Person
    def initialize(attributes)
      @attributes = attributes
    end

    def to_h
      {
        name: name,
        email: email
      }
    end

    def active?
      @attributes['active']
    end

    def email
      @attributes['emailAddress']
    end

    def name
      "#{@attributes['firstName']} #{@attributes['lastName']}"
    end
  end

程序码也变得更直观跟可读性了

  response = Request.call('some_url')
  parser = PeopleParser.new(response)

  eligible_users = parser.people.select(&:active?).map(&:to_h)

参考资料

My blog


<<:  辛酸写史- 下回见

>>:  【Day30】Pipelined 加法器

Day24. form_tag 与 simple_form_for 的用法 - 表单 part2

前一天,我们使用了simple_form_for提到了新增表单写法,而今天要讲一个上传情境。这个上传...

Day 26 设定 Redux 环境

第 26 天 ! 今天我们来试着把 redux 的环境建立起来吧, 安装 redux 套件: yar...

RISC-V on Rust 从零开始(9) - 实作memory model

CPU指令可以分成两大类,一是操作CPU内部暂存器的算术逻辑指令,一是存取记忆体,也就是所谓的loa...

【Day 28】JavaScript Promise

Promise 是甚麽? Promise 是 ES6 引入的标准之一。 Promise 字面上的意思...

【在 iOS 开发路上的大小事-Day29】浅谈 iOS 的 Background Modes

先前在研究如何让 App 在背景多存活久一点 有稍微去了解了一下 iOS 的 Background ...