ocaml,Functors:依赖注入

时间:2016-01-31 05:58:37

标签: dependency-injection ocaml

Real World Ocaml Chapter 9中关于仿函数:

  

依赖注入

     

使系统的某些组件的实现可以交换。当您想要模拟零件时,这尤其有用   您的系统用于测试和模拟目的。

但我没有理解这个想法。 我还查看了维基百科关于DI的内容 - 但实际上我没有用测试和模拟目的来捕捉这些关系。

2 个答案:

答案 0 :(得分:6)

Dependency injection是一种软件工程技术,其目的是减少程序的两个子系统之间的相互依赖性。这项技术的一个非常重要的细节是它不涉及两个,而是三个子系统:

  • 服务,
  • 使用
  • 的客户
  • 注射器,其职责是为客户准备服务。

后一个子系统,其责任,一个经常被忽视但至关重要的细节:这意味着客户端对服务的了解与公共接口一样少,这意味着可以轻松使用模拟服务来测试客户端。 / p>

假设我们编写了一个通过网络与键值存储进行通信的应用程序。键值存储具有以下签名:

module type AbstractKeyValueStoreService =
sig
   exception NetworkError
   type t
   val list : t -> string
   val find : t -> string -> string option
   val set : t -> string -> string -> unit
end

如果我们通过 AbstractKeyValueStoreService 类型的模块将客户端代码编写为客户端参数,我们可以在使用 set 函数时测试我们的应用程序对网络错误的弹性只需提供模拟服务,而无需实际创建网络错误:

module KeyValueStoreServiceFailingOnSet =
struct
  exception NetworkError
  type t = unit
  let list () = [ "a"; "b"]
  let find = function
    | "a" -> Some("x")
    | "b" -> Some("y")
    | _ -> None
  let set _ _ = raise NetworkError
end

如果我们的客户端是由 AbstractKeyValueStoreService 类型的模块进行参数化编写的,那么很容易为这个软件组件编写测试,其中模拟服务遵循一个或多或少复杂的交互脚本客户。

使用模块作为参数可能不是一个“惊天动地的想法”,但重要的是要知道这个想法如何用于解决重要的软件工程问题。这就是“真实世界OCaml”的作者似乎所做的。

答案 1 :(得分:0)

在我看来,他们只是想表明术语"依赖注入"可以看出是指完整模块的参数。这就是OCaml仿函数的含义:参数也是模块的模块。

这有很多用途,不仅仅是测试和模拟。但当然你可以用它来做那些。例如,您可以使用它来提供" mock"测试过程中的模块,用于替换在测试环境中难以再现的系统的某些部分。

一种看待这种情况的方法是"依赖注入"并不像它的追随者想要你想的那样有趣或新颖。至少这是我个人的想法。使用模块作为参数并不是一个令人震惊的想法,它已经在ML语言中存在了几十年。在Angular(至少)中,这与一个单独的概念混淆,即使函数参数的名称在语义上有意义。那(恕我直言)是一个错误。