Skip to content

Instantly share code, notes, and snippets.

@werediver
Last active March 18, 2020 10:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save werediver/66ff8f13c900e9871070 to your computer and use it in GitHub Desktop.
Save werediver/66ff8f13c900e9871070 to your computer and use it in GitHub Desktop.
Service Locator pattern implementation in Swift 2 with lazy (on demand) service initialization.
protocol ServiceLocator {
func getService<T>() -> T?
}
final class LazyServiceLocator: ServiceLocator {
/// Registry record
enum RegistryRec {
case Instance(Any)
case Recipe(() -> Any)
func unwrap() -> Any {
switch self {
case .Instance(let instance):
return instance
case .Recipe(let recipe):
return recipe()
}
}
}
/// Service registry
private lazy var reg: Dictionary<String, RegistryRec> = [:]
private func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
func addService<T>(recipe: () -> T) {
let key = typeName(T)
reg[key] = .Recipe(recipe)
}
func addService<T>(instance: T) {
let key = typeName(T)
reg[key] = .Instance(instance)
//print("Service added: \(key) / \(typeName(instance))")
}
func getService<T>() -> T? {
let key = typeName(T)
var instance: T? = nil
if let registryRec = reg[key] {
instance = registryRec.unwrap() as? T
// Replace the recipe with the produced instance if this is the case
switch registryRec {
case .Recipe:
if let instance = instance {
addService(instance)
}
default:
break
}
}
return instance
}
}
// Demo
// Services declaration
protocol S1 {
func f1() -> String
}
protocol S2 {
func f2() -> String
}
// Services imlementation
class S1Impl: S1 {
let s2: S2
init(s2: S2) {
self.s2 = s2
}
func f1() -> String {
return "S1 OK"
}
}
class S2Impl: S2 {
func f2() -> String {
return "S2 OK"
}
}
// Service Locator initialization
let sl: ServiceLocator = {
let sl = LazyServiceLocator()
sl.addService { S1Impl(s2: sl.getService()!) as S1 }
sl.addService { S2Impl() as S2 }
return sl
}()
// Test run
let s1: S1? = sl.getService()
let s2: S2? = sl.getService()
//let s2_: S2? = sl.getService()
print(s1?.f1() ?? "S1 NOT FOUND") // S1 OK
print(s2?.f2() ?? "S2 NOT FOUND") // S2 OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment