我读过这篇文章好几遍:
http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html
我想我明白了。不过,有件事我还不太明白。
查看他的UserService示例,我看到他设置了UserRepositoryComponent来封装UserRepository。但我不明白为什么UserRepositoryComponent扮演两个角色:它封装UserRepository并提供对UserRepository对象的引用。
如果我想要创建一个依赖于两个UserRepository实例的服务,我将如何使用这种模式。也许新服务的工作是将用户从“源”UserRepository复制到“目标”UserRepository。所以我在想象这样的事情:
trait CopyUserServiceComponent {
val source: UserRepositoryComponent
val destination: UserRepositoryComponent
class CopyUserServiceComponent {
...
}
}但这与最初的模式不同。在本例中,我定义了组件本身中的依赖项,而不是从其他组件继承它们。但在我看来,这是正确的方法:组件应该声明它们的依赖关系,而不是它们包含的服务的实例。
我在这里错过了什么?
发布于 2010-11-02 21:18:09
在本例中,我定义了组件本身中的依赖项,而不是从其他组件继承它们。
蛋糕模式不使用继承来声明依赖项。你在UserServiceComponent中看到“扩展”了吗?
但在我看来,这是正确的方法:组件应该声明它们的依赖关系,而不是它们包含的服务的实例。
但这正是蛋糕模式所做的:声明依赖关系!如果这个例子包含的是def userRepositoryFactory = new UserRepository而不是val userRepository = new UserRepository,那就更清楚了吗?
那么,让我们回到您的例子:
trait CopyUserServiceComponent {
val source: UserRepositoryComponent
val destination: UserRepositoryComponent
class CopyUserServiceComponent {
...
}
}让我们看看我们不能用它做的事情:
trait CopyUserServiceComponent {
// The module will need to see my internals!
private val source: UserRepositoryComponent
private val destination: UserRepositoryComponent
class CopyUserServiceComponent {
...
}
}
trait CopyBigUserServiceComponent extends CopyServiceComponent {
// Any change in implementation will have to be reflected in the module!
val tmp: UserRepositoryComponent
...
}另一方面..。
trait UserRepositoryComponent {
val userRepositoryFactory: () => UserRepository
class UserRepository {
...
}
}
trait CopyUserServiceComponent {
self: UserRepositoryComponent =>
// No problem here
private val source: UserRepository = userRepositoryFactory()
private val destination: UserRepository = userRepositoryFactory()
class CopyUserServiceComponent {
...
}
}
trait CopyBigUserServiceComponent extends CopyServiceComponent {
self: UserRepositoryComponent =>
// No problem here either
val tmp: : UserRepository = userRepositoryFactory()
...
}编辑
作为答案的补充,让我们考虑两种不同的需求:
UserRepository实例。在这种情况下,您在错误的级别上应用了模式。在Jonas的例子中,UserRepository处于工厂级--提供单例。
因此,在这种情况下,您不会做UserRepository和UserRepositoryComponent,而是,比如说,UserRepositoryFactory和UserRepositoryFactoryComponent。
UserRepository。在这种情况下,只需做这样的事情:
trait UserRepositoryComponent {
val sourceUserService: UserService
val destinationUserService: UserService
class UserService ...
}发布于 2010-11-02 20:15:21
我猜想,Jonas在他的文章中提到了一个被广泛接受的名为构建可伸缩应用程序的方法的复合软件建设,用几个词可以这样解释:整个应用程序(在元级上编排)是一个由独立组件构建的程序集,而这些组件又是其他组件和服务的组合。在复合软件方面,'cake' (示例中的ComponentRegistry对象)是组件('UserServiceComponent‘和'UserRepositoryComponent')等组件的集合,而在示例中,组件包含服务实现,这在现实世界中几乎不可能发生。
在您的示例中,您不需要定义内部类--您可以将工作流放在一个普通的方法中:
trait CopyUserServiceComponent {
val source: UserRepositoryComponent
val destination: UserRepositoryComponent
def copy = {...}
}它完全符合原始模式--蛋糕的基本特性不仅是通过自类型注释指定依赖项,而且还可以从具体的实现中抽象出来,直到您需要从组件构建程序集的时刻。
https://stackoverflow.com/questions/4078991
复制相似问题