2015-06-11 21 views
6

Yeni, ben hizmet kayıt yaratmaya çalıştığı:Swift'de bağımlılık enjeksiyonunun bundan daha iyi bir yolu var mı? swift için

class ServiceRegistry { 

    static var instance = ServiceRegistry() 

    private var registry = [String:AnyObject]() 
    private init(){} 

    func register<T>(key:T, value:AnyObject) { 
     self.registry["\(T.self)"] = value 
    } 

    func get<T>(_:T) -> AnyObject? { 
     return registry["\(T.self)"] 
    } 

} 

ama süper dostu değil:

Kayıt:

ServiceRegistry.instance.register(CacheServiceProtocol.self, value:ImageCacheService()) 

Al:

if let cache = ServiceRegistry.instance.get(CacheServiceProtocol) as? CacheServiceProtocol { ... } 

Daha iyi bir yol var mı? Bu faydalı olacaktır if let ...

cevap

6

Swinject içinde as? CacheServiceProtocol kurtulmak Swift için bir bağımlılık enjeksiyon çerçevesidir. Durumunuzda, as? ile döküm olmadan kullanabilirsiniz.

Kayıt:

let container = Container() 
container.register(CacheServiceProtocol.self) { _ in ImageCacheService() } 

Al:

let cache = container.resolve(CacheServiceProtocol.self)! 

İşte cacheCacheServiceProtocol türü olarak anlaşılır. Belirtilen tür kaydedilmemişse resolve yöntemi nil değerini döndürür. CacheServiceProtocol'un zaten kayıtlı olduğunu biliyoruz, bu nedenle ! ile zorla kapama kullanılır.

GÜNCELLEME

ben tam soruya cevap vermedi. Dökümün çıkarılması için bir uygulama, registry'daki değerler yerine fabrika kapanmalarını depolamaktır. İşte örnek. Ayrıca key türünü de değiştirdim.

class ServiceRegistry { 
    static var instance = ServiceRegistry() 

    private var registry = [String:Any]() 
    private init(){} 

    func register<T>(key:T.Type, factory:() -> T) { 
     self.registry["\(T.self)"] = factory 
    } 

    func get<T>(_:T.Type) -> T? { 
     let factory = registry["\(T.self)"] as?() -> T 
     return factory.map { $0() } 
    } 
} 

Kayıt:

ServiceRegistry.instance.register(CacheServiceProtocol.self) { 
    return ImageCacheService() 
} 

Al: @autoclosure kullanma

// The type of cache is CacheServiceProtocol? without a cast. 
let cache = ServiceRegistry.instance.get(CacheServiceProtocol.self) 

da iyi olabilir.

+0

Swinject hakkında Bu blog yayını da yararlı olabilir: https://yoichitgy.github.io/post/dependency-injection-framework-for-swift-introduction-to-swinject/ –

1

Service Locator tasarım desenini uygulama girişimini görüyorum. Bağımlılık Enjeksiyonu'un kendisi değil, ancak bu iki model aslında birbirini tamamlayabilir.

Swift 2'de de bir Service Locator uyguladım ve sonuçtan oldukça memnunum. Koduma bir göz atın: ServiceLocator.swift (kullanıma hazır) veya BasicServiceLocator.swift ve LazyServiceLocator.swift (kullanım örnekleri ile birlikte).

protocol ServiceLocator { 

    func getService<T>(type: T.Type) -> T? 
    func getService<T>() -> T? 

} 

extension ServiceLocator { 

    func getService<T>() -> T? { 
     return getService(T) 
    } 

} 

func typeName(some: Any) -> String { 
    return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)" 
} 

final class BasicServiceLocator: ServiceLocator { 

    // Service registry 
    private lazy var reg: Dictionary<String, Any> = [:] 

    func addService<T>(instance: T) { 
     let key = typeName(T) 
     reg[key] = instance 
     //print("Service added: \(key)/\(typeName(service))") 
    } 

    func getService<T>(type: T.Type) -> T? { 
     return reg[typeName(T)] as? T 
    } 

} 

Ve gösteri: Diğer posterleri biri belirttiği gibi

// Services declaration 

protocol S1 { 
    func f1() -> String 
} 

protocol S2 { 
    func f2() -> String 
} 

// Services imlementation 

class S1Impl: S1 { 
    func f1() -> String { 
     return "S1 OK" 
    } 
} 

class S2Impl: S2 { 
    func f2() -> String { 
     return "S2 OK" 
    } 
} 

// Service Locator initialization 

let sl: ServiceLocator = { 
    let sl = BasicServiceLocator() 
    sl.addService(S1Impl() as S1) 
    sl.addService(S2Impl() as S2) 
    return sl 
}() 

// Test run 

let s1 = sl.getService(S1) 
let s2: S2? = sl.getService(S2) 

print(s1?.f1() ?? "S1 NOT FOUND") // S1 OK 
print(s2?.f2() ?? "S2 NOT FOUND") // S2 OK 
0

, Servis Bulucu desen aslında DI değil

İşte temel kavramdır. Bazıları bile it's an anti-pattern demek için gidebilir. Sorunuza Genel olarak cevap

- Ben birinci sınıf DI yukarıda gerçekleştirmek için daha iyi bir yolu olduğuna inanıyorum. Benim önerim Typhoon kullanmak olacaktır ama çok umut verici görünüyor böyle üstüste temiz olarak Swift için kullanılabilir several other DI libs vardır.

İlgili konular