2016-01-12 5 views
5

मैं एक फ़ैक्टरी फ़ंक्शन बनाना चाहता हूं जो कक्षा प्रकार में लेता है और एक कन्स्ट्रक्टर देता है, ताकि मैं इसका उपयोग कर सकूं बाद में उस वर्ग का उदाहरण बनाने के लिए निर्माता।स्विफ्ट: एक फ़ैक्टरी फ़ंक्शन बनाना जो क्लास पैरामीटर को पैरामीटर के रूप में लेता है, और उस वर्ग के निर्माता का निर्माण करता है

कल्पना कीजिए कि मेरे पास दो वर्ग हैं, ऐप्पल और ऑरेंज, जो फलों के सबक्लास हैं। उन्हें unknownNumber के साथ प्रारंभ करने की आवश्यकता है जिसे मैं केवल बाद में ही जानता हूं।

class Apple: Fruit { 
    init(unknownNumber: Int) { 
     ... 
    } 
} 

class Orange: Fruit { 
    init(unknownNumber: Int) { 
     ... 
    } 
} 

मैं एक कारखाने समारोह है कि, एक कक्षा प्रकार में लेती है, ताकि मैं बाद में इस फ़ंक्शन को कॉल करें और फलों के विशिष्ट उपवर्ग को प्रारंभ कर सकते हैं, unknownNumber साथ बनाना चाहते हैं।

//concept: 
func makeFruit(typeOfFruit) -> (Int) -> Fruit { 
    return { (unknownNumber: Int) -> Fruit in 
     return typeOfFruit(unknownNumber) 
    } 
} 

एक orangeFactory बनाने के लिए, तो, मैं कर सकते हैं:

let orangeFactory = makeFruit(Orange)  

// then at a later time when I have the unknown number 
let orangeInstance = orangeFactory(unknownNumber) 

मैं बस unknownNumber एक आलसी चर बनाने का विकल्प के बारे में पता कर रहा हूँ, लेकिन मेरे विशिष्ट मामले में unknownNumber बस नहीं है एक संख्या और इसमें अन्य प्रक्रियाएं शामिल हैं, इसलिए संरचना को सरल रखने के लिए, जब मैं सब कुछ उपलब्ध हो, तो मैं केवल ऑब्जेक्ट बनाना चाहता हूं।

स्विफ्ट में ऐसा कुछ संभव है? मैं थोड़ी देर के लिए ऑनलाइन शोध कर रहा हूं और मुझे कोई सीधा जवाब नहीं मिल रहा था। किसी भी तरह की सहायता का स्वागत किया जाएगा!

उत्तर

4

चलिए पीछे की ओर काम करते हैं। अपने makeFruit समारोह में, आप और आपके Fruit सुपर क्लास की एक metatype रूप typeOfFruit पैरामीटर घोषित करने के लिए की आवश्यकता होगी स्पष्ट रूप प्रारंभकर्ता संदर्भ:

func makeFruit(typeOfFruit: Fruit.Type) -> (Int) -> Fruit { 
    return { (unknownNumber: Int) -> Fruit in 
     return typeOfFruit.init(unknownNumber: unknownNumber) 
    } 
} 

आप केवल एक metatype पर required initializers उपयोग कर सकते हैं, ताकि init जरूरतों होने के लिए इस तरह के रूप में चिह्नित:

class Fruit { 
    required init(unknownNumber: Int) { 
     // ... 
    } 
} 

बाकी सिर्फ काम करना चाहिए:

let orangeMaker = makeFruit(Orange.self) 
let tenOranges = orangeMaker(10) 
+0

यह एक उत्कृष्ट उत्तर है। विधि बहुत सरल लगती है, लेकिन स्विफ्ट के ऑब्जेक्ट सृजन मॉडल के कई छोटे idiosyncrasies के ज्ञान की भी आवश्यकता है। मैं अब यह कोशिश कर रहा हूं और अगर यह काम करता है तो जल्द ही आपको बताएगा! – gokeji

0

आप एक प्रोटोकॉल है जो आवश्यक init विधि को उजागर करता है के रूप में Fruit घोषणा कर सकते हैं, और जेनरिक समर्थन का इस्तेमाल करते हैं Switf में:

protocol Fruit { 
    init(unknownNumber: Int) 
} 

class Apple: Fruit { 
    required init(unknownNumber: Int) { 

    } 
} 

class Orange: Fruit { 
    required init(unknownNumber: Int) { 

    } 
} 

func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T { 
    return { T(unknownNumber: $0) } 
} 

makeFruit(Apple.self)(10) // returns an Apple 
makeFruit(Orange.self)(15) // returns an Orange 

यह भी आप makeFruit समारोह के परिणाम के रूप में सुरक्षा टाइप हो जाता है के रूप में ही है cls पैरामीटर द्वारा निर्दिष्ट प्रकार।

ध्यान दें कि यह एक कारखाना कार्य नहीं है, बल्कि केवल एक अग्रेषण है। लेकिन आप भी आगे जा सकते हैं और फलों से कुछ के लिए makeFruit को अनुकूलित, और यह है कि क्या यह एक कारखाने समारोह बना रही है:

class Apple: Fruit { 
    required init(unknownNumber: Int) { 

    } 

    init(color: String, unknownNumber: Int) { 

    } 
} 

func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T { 
    return { T(unknownNumber: $0) } 
} 

func makeFruit(cls: Apple.Type) -> Int -> Apple { 
    return { Apple(color: "red", unknownNumber: $0) } 
} 

makeFruit(Orange.self)(15) // an Orange 
makeFruit(Apple.self)(10) // a red Apple 

मान लिया जाये कि Apple वर्ग एक प्रारंभकर्ता है कि एक रंग को स्वीकार किया है कि, हम makeFruit ओवरराइड कर सकते हैं इस विशिष्ट वर्ग के लिए और फैक्ट्री विनिर्देशों के आधार पर एक डिफ़ॉल्ट रंग (या शायद एक गणना की गई) पास करें। स्विफ्ट के साथ आप पर बढ़ने वाली प्रकार की सुरक्षा खोने के बिना यह।

+1

प्रिय डाउन-वोटर! कृपया हमें बताएं, आप इस जवाब में क्या गलत देखते हैं। सभी उत्तरों (नाट्स, क्रिस्टिक के विज्ञापन एलैन) मूल रूप से एक ही दृष्टिकोण का उपयोग करते हैं और उनमें से सभी केवल छोटे विवरणों में भिन्न होते हैं। क्रिस्टिक का जवाब क्यों कम हो गया है ??? कृप्या! अगर किसी को कुछ जवाब पसंद नहीं है, तो हमें कारण बताएं! – user3441734

+0

हाय क्रिस्टिक, विचारशील उत्तर के लिए बहुत बहुत धन्यवाद। मैंने पहले जेनिक्स का उपयोग करके दृष्टिकोण नहीं माना था, और आपके जवाब ने मुझे कुछ चीजें सिखाईं। मैंने नाट के जवाब को स्वीकार कर लिया है क्योंकि यह एक बिल्कुल सीधे आगे फैशन में, जो मैंने पूछा है, वही प्रदान किया है, लेकिन मैं वास्तव में आपके इनपुट की भी सराहना करता हूं। क्षमा करें कि किसी ने इस जवाब को कम किया है; मैंने इसे ऊपर उठाया है। – gokeji

+1

लोगों को नीचे मतों के बारे में चिंता न करें, मैं नहीं :) – Cristik

1

यदि आप किसी फैक्ट्री एंट्री के पहचानकर्ता के रूप में कक्षा का उपयोग करने जा रहे हैं, तो आपको वास्तव में एक कारखाने की आवश्यकता नहीं है।कारखाना पैटर्न एक मनमानी पहचानकर्ता और वस्तु के एक समान वर्ग के बीच एक संकेत बनाता है।

var fruitFactory:[String:Fruit.Type] = [:] 

fruitFactory["Apple"] = Apple.self 
fruitFactory["Orange"] = Orange.self 
fruitFactory["Banana"] = Fruit.self 
fruitFactory["Grape"] = Fruit.self 

let tenOranges = fruitFactory["Orange"]!.init(unknownNumber:10) 

ध्यान दें कि फल कक्षा में अपने प्रारंभकर्ता के रूप में काम करने के लिए इस के लिए आवश्यक के रूप में चिह्नित किया जाना चाहिए:

स्विफ्ट में यह करने के लिए एक आसान तरीका एक शब्दकोश का प्रयोग है।

+0

उत्तर के लिए बहुत बहुत धन्यवाद। एक बार जब मैंने क्लास पर .init() को कॉल करने की संभावना के बारे में सीखा, तो उसने इतने सारे दरवाजे खोले! मैं मानता हूं कि आपका दृष्टिकोण कम से कम जटिल है, लेकिन मुझे स्वीकार्य उत्तर के रूप में नाट के उत्तर को चुनने के लिए मजबूर होना पड़ता है, क्योंकि उसने वही जवाब दिया जो मैंने मांगा था, और यह भी बेकार ढंग से काम करता है! – gokeji

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

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