Skip to content

Instantly share code, notes, and snippets.

@devxoul
Last active May 6, 2020 07:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devxoul/d154cb35010a04faa293b4c958b2c79d to your computer and use it in GitHub Desktop.
Save devxoul/d154cb35010a04faa293b4c958b2c79d to your computer and use it in GitHub Desktop.
Conceptual strong-typed DI container
protocol ContainerProtocol {
associatedtype Service
associatedtype Nested: ContainerProtocol
var service: Service { get }
var nestedContainer: () -> Nested { get }
}
struct TypedContainer<Service, Nested: ContainerProtocol>: ContainerProtocol {
let service: Service
let nestedContainer: () -> Nested
init(_ type: Service.Type, service: Service, nestedContainer: @autoclosure @escaping () -> Nested) {
self.service = service
self.nestedContainer = nestedContainer
}
func register<T>(_ type: T.Type, service newService: T) -> TypedContainer<T, Self> {
return TypedContainer<T, Self>(T.self, service: newService, nestedContainer: self)
}
func resolve(_ type: Service.Type) -> Service {
return self.service
}
typealias Nested1 = Nested
typealias Nested2 = Nested1.Nested
typealias Nested3 = Nested2.Nested
typealias Nested4 = Nested3.Nested
typealias Nested5 = Nested4.Nested
private var nestedContainer1: () -> Nested1 { self.nestedContainer }
private var nestedContainer2: () -> Nested2 { self.nestedContainer1().nestedContainer }
private var nestedContainer3: () -> Nested3 { self.nestedContainer2().nestedContainer }
private var nestedContainer4: () -> Nested4 { self.nestedContainer3().nestedContainer }
private var nestedContainer5: () -> Nested5 { self.nestedContainer4().nestedContainer }
func resolve(_ type: Nested1.Service.Type) -> Nested1.Service { return self.nestedContainer1().service }
func resolve(_ type: Nested2.Service.Type) -> Nested2.Service { return self.nestedContainer2().service }
func resolve(_ type: Nested3.Service.Type) -> Nested3.Service { return self.nestedContainer3().service }
func resolve(_ type: Nested4.Service.Type) -> Nested4.Service { return self.nestedContainer4().service }
func resolve(_ type: Nested5.Service.Type) -> Nested5.Service { return self.nestedContainer5().service }
}
struct Container: ContainerProtocol {
let service: Void = Void()
let nestedContainer: () -> Container = { (nil as Container?)!}
func register<T>(_ type: T.Type, service newService: T) -> TypedContainer<T, Container> {
return TypedContainer<T, Container>(T.self, service: newService, nestedContainer: self.nestedContainer())
}
func resolve(_ type: Service.Type) -> Service {
return (nil as Service?)!
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
protocol NetworkingProtocol {}
class Networking: NetworkingProtocol {}
protocol UserServiceProtocol {}
class UserService: UserServiceProtocol {}
protocol StyleServiceProtocol {}
class StyleService: StyleServiceProtocol {}
protocol UknownServiceProtocol {}
class UknownService: UknownServiceProtocol {}
let container = Container()
.register(NetworkingProtocol.self, service: Networking())
.register(UserServiceProtocol.self, service: UserService())
.register(StyleServiceProtocol.self, service: StyleService())
print(container)
print(container.resolve(NetworkingProtocol.self))
print(container.resolve(UserServiceProtocol.self))
print(container.resolve(StyleServiceProtocol.self))
print(container.resolve(UknownServiceProtocol.self)) // compile error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment