`
zhouchaofei2010
  • 浏览: 1117382 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

scala编程的蛋糕模式和依赖注入(转)

 
阅读更多

原文: http://colobu.com/2015/07/28/Scala-Cake-pattern-and-Dependency-Injection/

 

如果你是一个Java开发者,熟悉 依赖注入 模式, 深度依赖Spring框架的话,在使用Scala做开发时,会遇到一个问题,在Scala世界里,如何实现类似Spring框架的依赖注入呢?

尽管函数式编程的信徒认为他们不需要DI框架,高阶(high-order)函数足够了。但是对于同时支持面向对象的编程和函数式编程的Scala来说,依赖注入是很好的实现应用的一种设计模式。

蛋糕模式(Cake pattern)是Scala实现依赖注入的方式之一。

蛋糕模式是 Scala 之父 Martin Odersky 在其论文 Scalable Component Abstractions 中首先提到。

什么是蛋糕模式呢? 一个非正式的但是很形象的解释是:

  1. 蛋糕有很多风味, 你可以根据你的需要增加相应的风味。依赖注入就是增加调料。
  2. 蛋糕有很多层 (layer)。如果你想要一个更大的蛋糕你就可以增加更多的层。

我们先以Spring常用的User数据库读取的实现为例,看看Scala 风格的依赖注入(蛋糕模式)是如何实现的。

Java/Spring风格的依赖注入实现

一个传统的Spring实现是将程序划分为"Repository"层(DAO layer) 和Service层。

case class User (name:String)

trait UserRepository {

def create(user: User)

def find(name: String)

def update(user: User)

def delete(user: User)

}

class MockUserRepository extends UserRepository {

def create(user: User) = println( "creating user: " + user)

def find(name: String) = println( "finding user: " + name)

def update(user: User) = println( "udating user: " + user)

def delete(user: User) = println( "deleting user: " + user)

}

class UserService {

@Resource

var userRepository: UserRepository = _

def create(user: User) = userRepository.create(user)

def find(name: String) = userRepository.find(name)

def update(user: User) = userRepository.update(user)

def delete(user: User) = userRepository.delete(user)

}

我们可能有多个UserRepository的实现, 比如JPA, JDBC, Hibernate, iBATIS 等,然后将具体的实现通过Spring注入到 UserService中。这里我们用一个Mock来简单这些这个Trait, 然后模拟Spring注入,(Spring会根据配置和Reflect自动实现实例化和注入,这里我们只是模拟其原理,并没有使用Spring框架):

object Main extends App {

val service = new UserService()

val userRepository = new MockUserRepository()

service.userRepository = userRepository // inject userRepository into userService

service.create(User( "user" ))

}

Scala/Cake pattern实现依赖注入

和上面的代码类似,我们有三个class/trait:UserRepository,MockUserRepository和UserService, 其中MockUserRepository是UserRepository的具体实现,

现在我们想把MockUserRepository注入到UserService。注意UserService和UserRepository目前没有任何依赖关系。

Scala的蛋糕模式中我们需要声明几个Component:

trait UserRepositoryComponent {

val userRepository:UserRepository

}

trait UserServiceComponent {

this : UserRepositoryComponent =>

val userService: UserService

}

这里使用 self-type annotation 声明UserServiceComponent需要UserRepositoryComponent(this: UserRepositoryComponent =>)。 如果需要多个依赖,可以使用下面的格式:

this : Foo with Bar with Baz =>

剩下的就是注入了,生成一个ComponentRegistry对象:

object ComponentRegistry extends UserServiceComponent with UserRepositoryComponent {

override val userRepository: UserRepository = new MockUserRepository

override val userService: UserService = new UserService(userRepository)

}

挺漂亮的实现, 如果相应的依赖没有提供,或者拼写错误等,编译时能立刻提示我们。

这还有一个好处就是所有的对象都是val类型的。

这样你就可以通过ComponentRegistry.userService来使用顶层的组件了。

这样我们可以实现一种"干净"的方式实现不同的组件注入,比如我们想单元测试userService,其中它的依赖userRepository通过mock的方式提供:

import org.scalatest.mock.MockitoSugar

import org.mockito.Matchers._

import org.mockito.Mockito._

trait TestEnvironment extends UserServiceComponent with UserRepositoryComponent {

val userRepository = MockitoSugar.mock[UserRepository]

val userService = new UserService(userRepository)

}

object Test extends App with TestEnvironment {

val user = User( "user" )

userService.create(user)

verify(userRepository, times( 1 )).create(any[User])

}

可以很方便的为测试实现新的依赖注入,其中userRepository由mock实现。

这就是蛋糕模式的实现。通过 component trait 抽象接口和依赖,最后在一个ComponentRegistry注入各个具体的实现。

 

 

分享到:
评论

相关推荐

    蛋糕

    1. **软件开发中的“蛋糕”模式**:在编程领域,"蛋糕模式"(Cake Pattern)是一种设计模式,源于Scala编程语言。它允许模块化的应用程序构建,通过依赖注入来管理组件间的依赖关系。这种模式鼓励使用trait(特质)...

    智慧城市-2012年NEC智慧城市解决方案.zip

    智慧城市-2012年NEC智慧城市解决方案.zip

    IBMERP实施应收模块业务方案和用户操作手册手册超详.doc

    IBMERP实施应收模块业务方案和用户操作手册手册超详.doc

    spring-boot-1.4.4.RELEASE.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    spring-boot-2.4.0.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    JAVA保存计算过程的计算器课程设计报告样本.doc

    JAVA保存计算过程的计算器课程设计报告样本.doc

    scratch少儿编程逻辑思维游戏源码-像素任务.zip

    scratch少儿编程逻辑思维游戏源码-像素任务.zip

    spring-boot-1.4.6.RELEASE.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    spring-boot-2.6.9.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    spring-boot-1.5.14.RELEASE.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    rocksdbjni-6.22.1.1.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    scratch少儿编程逻辑思维游戏源码-死亡锯.zip

    scratch少儿编程逻辑思维游戏源码-死亡锯.zip

    FPGA单精度浮点数运算及PID控制的Verilog实现资料包

    内容概要:本文档介绍了一套完整的FPGA工程项目资料包,涵盖了单精度浮点数运算(加减乘除、开方)、浮点数与整数互转以及PID控制算法的Verilog实现。每个项目都包含了详细的工程代码、测试平台(testbench)和相关说明文件。此外,还提供了MATLAB文件用于验证PID算法的准确性,以及一个小工具用于浮点数和整数的转换。所有代码均为纯Verilog编写,不依赖于任何IP核,便于用户自定义修改和优化。 适合人群:对FPGA开发感兴趣的电子工程师、硬件开发者、科研人员及高校师生。 使用场景及目标:① 学习和掌握FPGA环境下单精度浮点数运算的基本原理及其具体实现方法;② 探索并理解PID控制算法在实际系统中的应用;③ 利用提供的MATLAB文件和小工具辅助教学或研究工作。 其他说明:资料包内的所有工程均可直接在Altera平台上进行仿真测试,帮助使用者快速入门并深入理解各个模块的功能特性。

    IBM企业内容管理解决方案.doc

    IBM企业内容管理解决方案.doc

    update9-20250501.5.208.slice.img.7z.003

    小雉系统分卷源码,修正系统安全问题

    rocksdbjni-6.25.3.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    spring-boot-2.3.8.RELEASE.jar中文-英文对照文档.zip

    # 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    scratch少儿编程逻辑思维游戏源码-我的 scratch 旅行.zip

    scratch少儿编程逻辑思维游戏源码-我的 scratch 旅行.zip

    scratch少儿编程逻辑思维游戏源码-太空派对.zip

    scratch少儿编程逻辑思维游戏源码-太空派对.zip

    冷冻站控制系统设计与实现——基于WinCC上位机与400冗余系统的图纸及程序解析

    内容概要:本文详细介绍了冷冻站控制系统的设计与实现,重点在于WinCC上位机和400冗余系统的应用。文中首先阐述了WinCC上位机的作用及其设计要点,如数据采集、处理、存储和报警显示等功能模块,并对其响应速度进行了优化。接着探讨了400冗余系统在提高系统可靠性方面的作用,通过多控制器备份机制确保系统稳定运行,并引入了故障诊断技术。最后,提供了详细的系统图纸(包括电路图、接线图)和程序代码(涵盖WinCC上位机程序及400冗余系统的控制逻辑),方便用户进行安装、调试和维护。 适用人群:从事工业自动化领域的工程师和技术人员,尤其是那些需要理解和实施冷冻站控制系统的专业人士。 使用场景及目标:适用于新建或改造冷冻站项目,旨在帮助技术人员掌握WinCC上位机和400冗余系统的具体应用,从而构建高可靠性、高实时性的冷冻站控制系统。 其他说明:文章不仅提供了理论指导,还附带实际操作所需的图纸和程序,便于读者直接应用于工程项目中。此外,作者对未来的技术发展方向进行了展望,强调将持续优化和升级系统,以适应不断变化的工业需求。

Global site tag (gtag.js) - Google Analytics