当被问及Scala中的依赖注入时,很多答案都指向使用Reader Monad,无论是来自Scalaz还是只是自己编写.有很多非常明确的文章描述了这种方法的基础知识(例如,Runar的演讲,Jason的博客),但我没有设法找到更完整的例子,我没有看到这种方法的优势超过例如更多传统的"手动"DI(参见我写的指南).最有可能的是我错过了一些重要的观点,因此问题就出现了.
举个例子,我们假设我们有这些类:
trait Datastore { def runQuery(query: String): List[String] }
trait EmailServer { def sendEmail(to: String, content: String): Unit }
class FindUsers(datastore: Datastore) {
def inactive(): Unit = ()
}
class UserReminder(findUser: FindUsers, emailServer: EmailServer) {
def emailInactive(): Unit = ()
}
class CustomerRelations(userReminder: UserReminder) {
def retainUsers(): Unit = {}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我使用类和构造函数参数进行建模,这与"传统"DI方法非常相似,但是这个设计有几个好的方面:
UserReminder不知道FindUsers需要数据存储.功能甚至可以在单独的编译单元中IO如果我们想要捕获效果等,"业务逻辑"方法可以返回包含在monad中的值.怎么能用Reader monad建模呢?保留上面的特性会很好,因此很清楚每个功能需要什么样的依赖关系,并隐藏一个功能与另一个功能的依赖关系.请注意,使用classes更多的是实现细节; 也许使用Reader monad的"正确"解决方案会使用其他东西.
我找到了一个有点相关的问题,暗示: