我试图在Swift中理解DI
。
我知道有Swinject
等框架可以为DI
提供帮助,但是我很想自己理解这一点,并且不会使用太多框架的魔力。
以下面的代码为例。
我的ProfileService
的初始化方法只会继续增长,并且随着此 pseudo 服务的扩展越来越胖,并且由于项目包含多个类,因此将重复相同的模式很多很多次。
如何避免这种情况?我希望找到一种支持简单维护的方法,同时仍能获得直接和简单代码注入的所有好处。
我正在考虑也许使用Protocol
和Struct
来包含依赖项并将其注入,但是无法理解如何最好地实现它。
import UIKit
class UserService {
func currentUser() -> String {
return "some username"
}
}
class AvatarService {
func currentUserAvatarUrl() -> String {
return "https://foo.bar/image.png"
}
}
class MessageService {
func currentInbox() -> [String:String] {
return [
"9279n1n2283":"something something",
"m2j292i2m2n":"something something something"
]
}
}
class ProfileService {
private let userService: UserService
private let avatarService: AvatarService
private let messageService: MessageService
init(userService: UserService, avatarService: AvatarService, messageService: MessageService) {
self.userService = userService
self.avatarService = avatarService
self.messageService = messageService
}
func getLoggedInUser() -> String {
return userService.currentUser()
}
func getUserAvatar() -> String {
return avatarService.currentUserAvatarUrl()
}
func getInboxMessages() -> [String:String] {
return messageService.currentInbox()
}
}
let userService = UserService()
let avatarService = AvatarService()
let messageService = MessageService()
let profileService = ProfileService(userService: userService, avatarService: avatarService, messageService: messageService)
profileService.getLoggedInUser()
profileService.getUserAvatar()
profileService.getInboxMessages()
答案 0 :(得分:0)
我的建议是根本不要直接对这些类进行依赖注入。我会做这样的事情:
import Foundation
// MARK: Protocols
protocol UserService {
var username: String { get }
}
protocol AvatarService {
var userAvatarURL: URL { get }
}
protocol MessageService {
var inbox: [String: String] { get }
}
protocol GlobalServiceContext {
var userService: UserService { get }
var avatarService: AvatarService { get }
var messageService: MessageService { get }
}
// MARK: Mock Implementations
class MockUserService: UserService {
let username = "test_user"
}
class MockAvatarService: AvatarService {
let userAvatarURL = URL(string: "https://en.wikipedia.org/static/images/project-logos/enwiki.png")!
}
class MockMessageService: MessageService {
let inbox = [
"test subject 1": "test message 1",
"test subject 2": "test message 2",
"test subject 3": "test message 3",
]
}
class MockServiceContext: GlobalServiceContext {
let userService: UserService = MockUserService()
let avatarService: AvatarService = MockAvatarService()
let messageService: MessageService = MockMessageService()
}
// MARK: Mock Implementations
class ProdUserService: UserService {
// TODO: Substitute real implementation here
let username = "prod_user"
}
class ProdAvatarService: AvatarService {
// TODO: Substitute real implementation here
let userAvatarURL = URL(string: "https://en.wikipedia.org/static/images/project-logos/enwiki.png")!
}
class ProdMessageService: MessageService {
let inbox = [ // TODO: Substitute real implementation here
"Prod subject 1": "Prod message 1",
"Prod subject 2": "Prod message 2",
"Prod subject 3": "Prod message 3",
]
}
class ProdServiceContext: GlobalServiceContext {
let userService: UserService = ProdUserService()
let avatarService: AvatarService = ProdAvatarService()
let messageService: MessageService = ProdMessageService()
}
// MARK: Usage
let ServiceContext: GlobalServiceContext = MockServiceContext()
class ProfileService {
var username: String { return ServiceContext.userService.username }
var userAvatarURL: URL { return ServiceContext.avatarService.userAvatarURL }
var inbox: [String:String] { return ServiceContext.messageService.inbox }
}
let profileService = ProfileService()
print(profileService.username)
print(profileService.userAvatarURL)
print(profileService.inbox)
它包含您的所有全局状态(您的API,服务,数据库等):
答案 1 :(得分:0)
使用DI时,胖的初始值设定项可能是不良设计的标志,并表明您的组件并非简单的任务。因此,您应该尝试使其断开并解耦。