将不纯函数转换为纯函数改进-Scala

时间:2018-08-30 19:07:38

标签: scala functional-programming pure-function

object IO {

  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class SongService {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName

    //impure call
    val geniusStringResponse = IO.getHtmlFromWebsiteViaHttp(searchLink, apiKey)

   //Extra processing on geniusStringResponse
  }
}

我目前的设计是我将有一个服务类,该服务类负责通过外部API获取一些信息。现在我知道不可能拥有100%的纯函数。

我的问题:处理需要连接到Scala / FP中的外部API的情况的最佳方法是什么?目的是通过最小化不纯函数来拥有最适当的“函数式编程风格”

当前,我将所有API调用封装在IO对象中。这样够合适吗?我看到了用于情况的单子示例。在这种情况下,我应该合并单子风格吗?

1 个答案:

答案 0 :(得分:0)

这并不是一个FP问题,因为就FP而言,我看不到您的代码有任何问题,但是我认为应该使用依赖项注入,例如,为了进行测试,您可以可以将测试类替换为具有保证响应的IO。像这样:

abstract class IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String
}

class IOImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class IOTestImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = ??? //some test HTML
}

然后为您服务:

class SongService(io: IO) {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName
    val geniusStringResponse = io.getHtmlFromWebsiteViaHttp(searchLink, apiKey)
   //Extra processing on geniusStringResponse
  }
}

然后,当实例化SongService时,在测试中将其传递给IOTestImpl,否则将IOImpl传递给它。您可能会在dependency injectiondatabase access objects上找到一些相关信息。