Last active
December 16, 2016 02:30
-
-
Save portellaa/d1f4aad2916e91d7c09e798f3c5f93f7 to your computer and use it in GitHub Desktop.
Service ๐ with lazy capabilities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: Playground - noun: a place where people can play | |
import Foundation | |
typealias LazyServiceClosure<Service> = () -> (Service) | |
enum ServiceLocatorError: Error { | |
case duplicateService(String) | |
case inexistentService | |
case serviceTypeMismatch | |
case lazyDuplicatedService(String) | |
} | |
final class ServiceLocator { | |
static lazy var sharedInstance = ServiceLocator() | |
private var services = [String : Any]() | |
private lazy var lazyServices = [String : LazyServiceClosure<Any>]() | |
func register<Service>(service: Service, serviceName: String? = nil) throws { | |
let name = buildName(for: Service.self, serviceName) | |
try checkForDuplicatedService(for: name) | |
services[name] = service | |
} | |
func register<Service>(serviceName: String? = nil, _ lazyInit: @escaping LazyServiceClosure<Service>) throws { | |
let name = buildName(for: Service.self, serviceName) | |
try checkForDuplicatedService(for: name) | |
lazyServices[name] = lazyInit | |
} | |
func unregister<Service>(_: Service, serviceName: String? = nil) throws { | |
let _: Service = try locate(serviceName) | |
let name = buildName(for: Service.self, serviceName) | |
services[name] = nil | |
} | |
func unregisterAll() { | |
services.removeAll() | |
} | |
func get<Service>(serviceName: String? = nil) throws -> Service { | |
return try locate(serviceName) | |
} | |
// MARK: - Private Methods | |
private func locate<Service>(_ serviceName: String? = nil) throws -> Service { | |
let name = buildName(for: Service.self, serviceName) | |
if let lazyServiceClosure = lazyServices[name] { | |
// Remove closure since this is already initialised | |
lazyServices[name] = nil | |
let service: Service = try checkIfServiceValid(lazyServiceClosure()) | |
try register(service: service) | |
} | |
guard let anyService = services[name] else { | |
throw ServiceLocatorError.inexistentService | |
} | |
return try checkIfServiceValid(anyService) | |
} | |
private func buildName<Service>(`for` _: Service.Type, _ serviceName: String? = nil) -> String { | |
return serviceName ?? "\(Service.self)" | |
} | |
private func checkIfServiceValid<Service>(_ anyService: Any) throws -> Service { | |
guard let service = anyService as? Service else { | |
throw ServiceLocatorError.serviceTypeMismatch | |
} | |
return service | |
} | |
private func checkForDuplicatedService(`for` name: String) throws { | |
guard services[name] == nil else { | |
throw ServiceLocatorError.lazyDuplicatedService(name) | |
} | |
} | |
} | |
// Test ServiceLocator | |
struct TestA { | |
let testA = "testA works" | |
} | |
struct TestB { | |
let testB = "testB works" | |
} | |
let serviceLocator = ServiceLocator.sharedInstance | |
try! serviceLocator.register(service: TestA()) | |
try! serviceLocator.register() { TestB() } | |
let testA: TestA = try! serviceLocator.get() | |
print(testA.testA) | |
let testB: TestB = try! serviceLocator.get() | |
print(testB.testB) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment