当我需要从两个不同的 Web 服务获取控制器数据时,我应该如何使用 MVVM 和依赖注入?
How should I use MVVM and Dependency Injection when I need to fetch a controller data from two different web services?
我在我的 swift 项目中使用 MVVM 设计模式。在视图控制器中,我需要从两个不同的 Web 服务获取数据。所以我需要在控制器中创建一个视图模型,如下所示:
class MyViewController: UIViewController {
var viewModel: MyViewModel = MyViewModel(repository: NetworkLayer(service1: WebService1(), service2: WebService2()))
override func viewDidLoad() {
super.viewDidLoad()
viewModel.getData(catUrl, categoryId: "\(catId)")
}
}
视图模型负责从服务器获取数据并通过控制器更新视图。我找到了存储库设计模式和依赖注入来解决我的问题:
class MyViewModel {
var webService1: WebService1?
var webService2: WebService2?
init(repository: NetworkLayer) {
self.webService1 = repository.service1
self.webService2 = repository.service2
}
func getData(_ url: String, categoryId: String) {
webService1?.delegate = self
webService1?.getData(urlCode: url)
webService2?.delegate = self
webService2?.getProducts(queryString: "sortby=14&pageno=0&status=2&pagesize=20&category=c\(categoryId)")
}
}
class NetworkLayer: WebService1Delegate, WebService2Delegate {
var webService1: WebService1?
var webService2: WebService2?
init(service1: WebService1, service2: WebService2) {
self.service1 = service1
self.service2 = service2
}
}
谁能告诉我我处理这种情况的方法是否正确?如果没有,最好的应对方式是什么?
如果您想正确实施存储库模式,我建议您应该使用协议。例如,您将创建这样的协议
protocol RepositoryProtocol {
func fetchInformation() -> String
}
因此您的服务 classes 必须实现这一点。所以这是一个例子
class MyService: RepositoryProtocol {
func fetchInformation() -> String {
return ""
}
}
为了安全起见,您还应该创建一个视图模型协议。
protocol ViewModel {
associatedtype Repo
init (withRepo repo: Repo)
}
所以这就是说,class符合此 ViewModel 协议的 es 将在视图模型中定义一些类型,并且必须将其注入到 init 方法中。还有好处,它不再是可选对象。
下面是视图模型的示例
struct MyViewModel : ViewModel {
typealias Repo = RepositoryProtocol
let repo : RepositoryProtocol
init(withRepo repo: Repo) {
self.repo = repo
}
}
所以在这里你可以看到,你的视图模型必须注入一个符合你在视图模型中定义的协议的对象class。如您所见,typealias 已用于表示此对象将属于 RepositoryProtocol 类型。您可以更新视图模型协议,以便它要求视图模型使用您需要的尽可能多的服务进行初始化
这是处理回购模式和依赖项注入的更好方法。
我在我的 swift 项目中使用 MVVM 设计模式。在视图控制器中,我需要从两个不同的 Web 服务获取数据。所以我需要在控制器中创建一个视图模型,如下所示:
class MyViewController: UIViewController {
var viewModel: MyViewModel = MyViewModel(repository: NetworkLayer(service1: WebService1(), service2: WebService2()))
override func viewDidLoad() {
super.viewDidLoad()
viewModel.getData(catUrl, categoryId: "\(catId)")
}
}
视图模型负责从服务器获取数据并通过控制器更新视图。我找到了存储库设计模式和依赖注入来解决我的问题:
class MyViewModel {
var webService1: WebService1?
var webService2: WebService2?
init(repository: NetworkLayer) {
self.webService1 = repository.service1
self.webService2 = repository.service2
}
func getData(_ url: String, categoryId: String) {
webService1?.delegate = self
webService1?.getData(urlCode: url)
webService2?.delegate = self
webService2?.getProducts(queryString: "sortby=14&pageno=0&status=2&pagesize=20&category=c\(categoryId)")
}
}
class NetworkLayer: WebService1Delegate, WebService2Delegate {
var webService1: WebService1?
var webService2: WebService2?
init(service1: WebService1, service2: WebService2) {
self.service1 = service1
self.service2 = service2
}
}
谁能告诉我我处理这种情况的方法是否正确?如果没有,最好的应对方式是什么?
如果您想正确实施存储库模式,我建议您应该使用协议。例如,您将创建这样的协议
protocol RepositoryProtocol {
func fetchInformation() -> String
}
因此您的服务 classes 必须实现这一点。所以这是一个例子
class MyService: RepositoryProtocol {
func fetchInformation() -> String {
return ""
}
}
为了安全起见,您还应该创建一个视图模型协议。
protocol ViewModel {
associatedtype Repo
init (withRepo repo: Repo)
}
所以这就是说,class符合此 ViewModel 协议的 es 将在视图模型中定义一些类型,并且必须将其注入到 init 方法中。还有好处,它不再是可选对象。
下面是视图模型的示例
struct MyViewModel : ViewModel {
typealias Repo = RepositoryProtocol
let repo : RepositoryProtocol
init(withRepo repo: Repo) {
self.repo = repo
}
}
所以在这里你可以看到,你的视图模型必须注入一个符合你在视图模型中定义的协议的对象class。如您所见,typealias 已用于表示此对象将属于 RepositoryProtocol 类型。您可以更新视图模型协议,以便它要求视图模型使用您需要的尽可能多的服务进行初始化
这是处理回购模式和依赖项注入的更好方法。