2015-06-11 2 views
6

नई स्विफ्ट के लिए, मैं एक सेवा रजिस्ट्री बनाने के लिए कोशिश कर रहा था:क्या स्विफ्ट में निर्भरता इंजेक्शन करने का कोई बेहतर तरीका है?

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)"] 
    } 

} 

लेकिन सुपर अनुकूल नहीं है:

रजिस्टर:

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

प्राप्त करें:

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

कोई बेहतर तरीका? if let ...

उत्तर

6

Swinject में as? CacheServiceProtocol से छुटकारा पाने के यह उपयोगी होगा स्विफ्ट के लिए एक निर्भरता इंजेक्शन रूपरेखा है। आपके मामले में, आप as? के साथ कलाकार के बिना इसका उपयोग कर सकते हैं।

रजिस्टर:

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

प्राप्त करें:

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

यहाँ cacheCacheServiceProtocol प्रकार के रूप में मान लिया जाता है। resolve विधि nil देता है यदि निर्दिष्ट प्रकार पंजीकृत नहीं है। हम जानते हैं कि CacheServiceProtocol पहले से ही पंजीकृत है, इसलिए ! के साथ बल-अनचाहे का उपयोग किया जाता है।

अद्यतन

मैं बिल्कुल सवाल का जवाब नहीं दिया। कास्ट को हटाने के लिए एक कार्यान्वयन registry में मूल्यों के बजाय कारखाने के बंदरगाहों को संग्रहित कर रहा है। उदाहरण यहाँ है। मैंने key के प्रकार को भी संशोधित किया।

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() } 
    } 
} 

रजिस्टर:

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

प्राप्त करें:

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

@autoclosure का उपयोग करना भी अच्छा हो सकता है।

+0

स्विंगजेक्ट के बारे में यह ब्लॉग पोस्ट भी सहायक हो सकता है: https://yoichitgy.github.io/post/dependency-injection-framework-for-swift-introduction-to-swinject/ –

1

मैं सेवा लोकेटर डिज़ाइन पैटर्न को लागू करने का प्रयास देखता हूं। यह निर्भरता इंजेक्शन स्वयं नहीं है, लेकिन ये दो पैटर्न वास्तव में एक-दूसरे को पूरक कर सकते हैं।

मैंने स्विफ्ट 2 में एक सेवा लोकेटर को भी लागू किया और मैं परिणाम से बहुत खुश हूं। यहां मेरे कोड पर एक नज़र डालें: ServiceLocator.swift (उपयोग करने के लिए तैयार) या BasicServiceLocator.swift और LazyServiceLocator.swift (उपयोग उदाहरणों के साथ)।

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 
    } 

} 

और प्रदर्शन:

// 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

के रूप में अन्य पोस्टर में से एक ने कहा, सेवा लोकेटर पैटर्न नहीं वास्तव में डि है

यहाँ मूल अवधारणा है। कुछ it's an anti-pattern कहने के लिए अब तक भी जाएंगे।

आपके प्रश्न के सामान्य उत्तर के रूप में - मुझे विश्वास है कि प्रथम श्रेणी डी उपरोक्त को पूरा करने का एक बेहतर तरीका है। मेरा सुझाव Typhoon का उपयोग करना होगा, लेकिन several other DI libs स्विफ्ट जैसे क्लीनस के लिए उपलब्ध है जो बहुत ही आशाजनक दिखता है।

संबंधित मुद्दे

 संबंधित मुद्दे