gpt4 book ai didi

ios - MVVM、依赖注入(inject)和过多的构造函数参数

转载 作者:可可西里 更新时间:2023-11-01 03:35:20 27 4
gpt4 key购买 nike

几个月来,我一直在使用 MVVM 和依赖项注入(inject)进行 iOS 开发,我对结果非常满意。代码非常清晰,也更容易测试。但是我一直在为一个问题而苦苦挣扎,但我还没有找到一个让我感到非常舒服的解决方案。

为了理解这个问题,我想给你一些背景知识。我一直在使用的最后一个应用程序是按以下方式/层构建的:

  • 模型
  • 查看模型
  • 查看/查看 Controller
  • 服务:知道如何处理 Twitter、Facebook 等外部服务的类。
  • 存储库:存储库是知道如何与应用程序的 REST API 资源交互的类。假设我们有一个博客应用程序,我们可以拥有用户资源和帖子资源。这些资源中的每一个都有几种方法。资源和存储库之间存在一对一的关系。

当应用程序启动时,我们有一个 Bootstrap 类来初始化应用程序并创建主视图模型。我们有一个限制,只有 View 模型可以创建其他 View 模型。例如,如果有一个包含元素列表的 View (在 iOS 中,它将用 UITableView 表示)和每个元素的详细 View ,通过在点击元素后将其推送到导航堆栈来呈现在列表中。我们所做的是让附加到 TableView Controller 的 View 模型创建详细 View 模型。 TableView Controller 监听 TableView 模型,然后通过创建详细 View Controller 并将其 View 模型传递给它来呈现详细 View 模型。所以 View Controller 不知道如何创建 View 模型,它只知道如何为该 View 模型创建 View Controller 。

父 View 模型负责将所有依赖项传递给 subview 模型。

当 View 层次结构中非常深的 View 模型需要其父 Controller 不需要的依赖项时,就会出现问题。例如访问某些外部 Web 服务的服务。因为它的父级没有那个依赖,所以它必须将它添加到它的依赖列表中,从而向构造函数添加一个新参数。想象一下,如果祖 parent 也没有依赖性,情况会怎样。

您认为什么是好的解决方案?可能的解决方案:

  • 单例:更难测试,它们基本上是全局状态
  • 一个工厂类:我们可以使用一组知道如何创建特定类型对象的工厂。例如 ServiceFactory 和 RepositoryFactory。服务工厂可以有创建服务的方法,例如:TwitterService、FacebookService、GithubService。存储库工厂可以知道如何为每个 API 资源创建一个存储库。在有几个工厂(2 个或 3 个)的情况下,所有 View 模型都可能依赖于这个工厂。

现在我们选择了工厂类解决方案,因为我们不需要使用单例,我们可以将工厂视为任何其他依赖项,这使得它相对容易测试。问题是它有点像一个好对象,并且通过拥有一个工厂,您实际上并不知道哪个是真正需要 View 模型的依赖项,除非您查看构造函数的实现以检查正在调用哪些工厂方法。

最佳答案

在我们的应用程序中,我们选择让我们的 View 模型通过依赖查找而不是依赖注入(inject)来访问它们的依赖。这意味着 View 模型只是传递一个包含必要依赖项的容器对象,然后从该容器对象中“查找”每个依赖项。

这样做的主要优点是系统中的所有对象都可以在容器定义中预先声明,与可能需要的七十八个左右的依赖项相比,传递容器非常简单。

任何依赖注入(inject)爱好者都会告诉你,依赖查找肯定是它的次等表亲,主要是因为依赖查找需要对象理解容器的概念(因此通常是提供它的框架),而依赖注入(inject)保持对象幸福地不知道其依赖项来自何处。但是,在这种情况下,我认为权衡是值得的。请注意,在我们的架构中,只是 View 模型进行了这种权衡——所有其他对象(例如您的“模型”和“服务”)仍然使用 DI。

还值得注意的是,依赖项查找的许多基本实现都将容器作为单例,但情况并非必须如此。在我们的应用程序中,我们有多个容器,它们只是将相关的依赖项“组合”在一起。如果不同的对象具有不同的生命周期,这一点尤其重要——一些对象可能永远存在,而其他对象可能只需要在某个用户事件进行时存在。这就是容器从 View 模型传递到 View 模型的原因——不同的 View 模型可能有不同的容器。这还允许您将装满模拟对象的容器传递给被测 View 模型,从而促进单元测试。

为了给原本抽象的答案提供一些具体性,下面是我们的一个 View 模型的外观。我们使用 Swinject框架。

class SomeViewModel: NSObject {
private let fooModel: FooModel
private let barModel: BarModel

init(container: Container) {
fooModel = container.resolve(FooModel.self)!
barModel = container.resolve(BarModel.self)!
}

// variety of code here that uses fooModel and barModel
}

关于ios - MVVM、依赖注入(inject)和过多的构造函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30571032/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com