2015-05-12 7 views
5

ठीक है तो मेरे पास मेरे प्रोजेक्ट में सहायक कार्यों का एक गुच्छा है जो मूल रूप से एनिम नामक कक्षा में था। मुझे आश्चर्य हुआ कि func vc class func घोषित करने के क्या फायदे हैं।क्लास func बनाम func बनाम कोई वर्ग घोषणा बनाम

चलें एक उदाहरण वर्ग के रूप में इस का उपयोग करें:

class Animate{ 
    func moveView(...){ 
     ... 
    } 
} 

तो मेरा मानना ​​है कि अगर मैं एक वर्ग समारोह मैं इतनी के रूप में वर्ग का दृष्टांत की जरूरत नहीं है की है।

Animate.moveView(...)

और अगर मैं सिर्फ समारोह की घोषणा समारोह के साथ होगा:

Animate().moveView(...)

लेकिन अगर मैं बिल्कुल के रूप में तो एक वर्ग के रूप में फ़ाइल नहीं घोषित करते हैं:

func moveView(...){ 
    ... 
} 

जब मैं फ़ंक्शन को कॉल करता हूं तो यह है:

moveView(...) 

कोई संकेत नहीं है कि कोड कहां से आया था और इसे इस परियोजना में कहीं भी इस्तेमाल किया जा सकता है।

इन तीन तरीकों के पेशेवरों और विपक्ष क्या हैं? कक्षा खराब अभ्यास की घोषणा नहीं कर रहा है? या, क्या कुछ बढ़त मामला है कि यह बहुत उपयोगी है? उदाहरण के लिए मेरी स्थिति में मुझे कक्षा के लिए कोई आवश्यकता नहीं है क्योंकि मैं केवल सहायक कार्यों को बना रहा हूं, न कि किसी ऑब्जेक्ट।

इस पर किसी भी अंतर्दृष्टि के लिए अग्रिम धन्यवाद!

+0

जब तक कि स्थानीय एमवीसी में फिनक नहीं है, मुझे कक्षाएं पसंद हैं क्योंकि आप जानते हैं कि वे कहां से आते हैं। किसी और के कोड को डीबग करने का प्रयास करें जहां यह मैशप है और आपके पास कोई सुराग नहीं है। –

उत्तर

9

ठीक है। ग्लोबल विधियों बनाम क्लास विधियों बनाम इंस्टेंस विधियां।

(अवधि विधि और समारोह परस्पर विनिमय कर रहे। विधि एक समारोह एक वस्तु द्वारा कार्यान्वित का तात्पर्य है, इसलिए मैं अवधि कार्य करने के लिए अवधि विधि पसंद करते हैं।)

एक उदाहरण विधि एक विधि है कि द्वारा किया जाता है है एक वर्ग के उदाहरण। एक उदाहरण विधि का आह्वान करने के लिए आपके पास उस कक्षा का एक उदाहरण होना चाहिए।

इंस्टेंस विधियों के पास उस ऑब्जेक्ट के इंस्टेंस वेरिएबल्स तक पहुंच है, इसलिए ऑब्जेक्ट कॉल के बीच राज्य की जानकारी को सहेज सकता है। (एक नेटवर्किंग क्लास में आप कई डाउनलोड ऑब्जेक्ट्स बना सकते हैं, जिनमें से प्रत्येक एक अलग यूआरएल से एक अलग फाइल के एक अलग फ़ाइल डाउनलोड का प्रबंधन करता है, और प्रत्येक के पास एक अलग प्रतिनिधि हो सकता है जो इसे डाउनलोड होने पर सूचित करता है)

क्लास विधियां एक उदाहरण से नहीं, कक्षा द्वारा खुद को बुलाया जाता है। यह आपके लिए काम करने के लिए ऑब्जेक्ट को प्रबंधित किए बिना सहायक कार्यों को आमंत्रित करना आसान बना सकता है। चूंकि कक्षा के तरीके कक्षा के एक उदाहरण से बात नहीं करते हैं, इसलिए वे प्रत्येक वस्तु के लिए अलग-अलग राज्य जानकारी को संरक्षित नहीं कर सकते हैं। आपके पास एक यूटिलिटी क्लास हो सकती है जो उदाहरण के लिए तारों पर स्थानीयकरण फ़ंक्शन करता है। स्थानीयकरण प्रक्रिया स्वयं निहित है। आप एक वर्ग फ़ंक्शन को कॉल करते हैं और एक स्ट्रिंग और उस भाषा में गुजरते हैं जिसे आप स्थानीयकृत करना चाहते हैं, और यह आपको परिणाम देता है। कॉल के बीच राज्य रखने की जरूरत नहीं है। इस तरह की एक कॉल

let frenchString = 
    LocalizationUtils.localizeString("English String", 
    toLanguage: "French") 

वैश्विक कार्य किसी भी विशेष वर्ग से संबंधित नहीं हो सकता है। वे पूरे मॉड्यूल के लिए वैश्विक हैं जिसमें उन्हें परिभाषित किया गया है। वे वर्ग कार्यों के समान हैं, सिवाय इसके कि वे किसी विशेष वर्ग के लिए विशिष्ट नहीं हैं।

+0

तो, आपकी राय में ग्लोबल फ़ंक्शन एक कोड गंध हैं और मुझे इसके बजाय कक्षा विधियों का उपयोग करना चाहिए? – Boid

+0

नहीं, सभी 3 में उनकी जगह है। क्लास फ़ंक्शंस को कार्यों के लिए तर्कसंगत रूप से समूहबद्ध करने के लिए एक स्पष्ट "नाम स्थान" बनाने का लाभ होता है। स्विफ्ट में ऑपरेटर ओवरलोडिंग वैश्विक कार्यों का एक उदाहरण है। यदि आप कक्षा के लिए "+" ऑपरेटर को परिभाषित करते हैं, तो यह एक वैश्विक कार्य होना चाहिए ताकि आप इसे किसी भी संदर्भ में आमंत्रित कर सकें। –

3

मैं @ डंकन सी के उत्तर से सहमत हूं (और ऊपर उठाया गया), लेकिन मैंने सोचा कि मैं कुछ अन्य पेशेवरों/विपक्ष में फेंक दूंगा।

मुझे क्लास विधियों पर वैश्विक कार्यों को पसंद है क्योंकि वैश्विक कार्य मेरी कक्षाओं को अव्यवस्थित नहीं करते हैं। मुझे अपने वर्ग दुबला और पतला रखना पसंद है। वैश्विक कार्यों को एक अलग फ़ाइल में रखा जा सकता है जिसे मैं किसी दिए गए प्रोजेक्ट में कॉपी और पेस्ट या आयात कर सकता हूं। तो मेरे पास AnimateHelperFunctions नामक मेरी परियोजना में एक फ़ाइल हो सकती है जो कि उस वर्ग से संबंधित वैश्विक कार्य है। एक दिए गए प्रोजेक्ट में केवल उनमें से कुछ की आवश्यकता हो सकती है, या उनमें से अधिकतर, या साथ ही साथ कुछ और जो मुझे पता है मुझे चाहिए। मैं उन फ़ाइलों को हटा सकता हूं जिन्हें मैं फ़ाइल से किसी दिए गए प्रोजेक्ट में उपयोग नहीं करता हूं ताकि फ़ाइल को साफ और ट्रिम कर सकें।

मुझे लगता है कि वैश्विक कार्य अधिक मॉड्यूलर हैं और मुझे एक ही समारोह के लिए एकल कार्यों को कारक बनाने के लिए प्रोत्साहित करते हैं - एक अच्छा वैश्विक सहायक कार्य जो वास्तव में एक चीज करता है और इसे पूरी तरह से समझा जा सकता है या कभी भी सामान्य और उपयोग किया जा सकता है अन्य संदर्भों में भी। आपके पास कभी-कभी एक परियोजना हो सकती है जहां आपको पता चलता है कि आपको कक्षा की आवश्यकता नहीं है - आपको बस इसके सहायक कार्य की आवश्यकता है, और वहां है।

मैं एक सौ साधारण वैश्विक कार्यों को पसंद करूंगा जिन्हें मैं चुन सकता हूं और एक विशाल ब्लोएटेड कक्षा से चुन सकता हूं।

आप विस्तार के साथ बहुत कुछ हासिल कर सकते हैं, ज़ाहिर है, और कुछ डिग्री के लिए यह स्वाद का विषय है, क्योंकि क्लास विधियों और वैश्विक कार्यों के बीच बहुत कम अंतर (कोई?) है, कक्षा के उपयोग के अलावा विधि आपको पूरी कक्षा के साथ खींचना है।

वैश्विक स्थिति के विपरीत, वैश्विक कार्य में कोई खतरा नहीं है। निश्चित रूप से, कोई भी इसे कॉल कर सकता है, लेकिन यह वर्ग विधियों के बारे में भी सच है, और वैश्विक कार्य केवल आपके द्वारा पारित तर्कों पर ही कार्य कर सकता है।

+0

अतिरिक्त जानकारी के लिए धन्यवाद :) – Boid

+0

मेरे लिए ऐसा लगता है जैसे आपको ओओपी मानसिकता को अपनाने की आवश्यकता है। ऐसा नहीं है कि आपके मुख्य बिंदु गलत हैं, लेकिन एक अच्छी तरह से डिजाइन ओओपी प्रोजेक्ट 100 गुना क्लीनर और उसी बेहद स्वच्छ, सही वैश्विक कार्यों के साथ उसी परियोजना के माध्यम से काम करना आसान लगेगा। मेरे पास एक परियोजना है जिसे मैं 300 से अधिक फाइलों और कोड की 200,000 लाइनों के साथ प्रबंधित करता हूं। हर बार जब मैं गंभीर रिफैक्टरिंग करता हूं, तो परियोजना हमेशा बेहतर दिखती है, और यह अधिक ओओपी बन जाती है। मेरे पास 0 वैश्विक कार्य हैं। मेरे पास कुछ स्थिर कार्य हैं। यदि मैं वैश्विक कार्य करना चाहता हूं, तो यह सामान्य प्रकार के विस्तार के रूप में लगभग हमेशा बेहतर होता है। – Sethmr

1

मेरे लिए, मैं static या class तरीकों का उपयोग या वर्ग के स्तर का गुण नियंत्रित करने के लिए मुझे लगता है कि विशेष रूप से class या sturct के कस्टमाइज़ किए गए उदाहरणों वापस जाने के लिए है। उदाहरण के लिए मुझे लगता है कि मेरे पास struct से नीचे है।

struct Person { 
    let firstName: String 
    let lastName: String 
} 

अब अगर मैं कुछ परीक्षण मामलों, जहां मैं Person के उदाहरण अपने परीक्षण कक्षाओं के कई में एक विशेष नाम John साथ प्रारंभ की जरूरत है लिख रहा हूँ, मैं एक सहायक static विधि बना सकते हैं।

extension Person { 
    static func john() -> Person { 
     return Person(firstName: "John", lastName: "Appleseed") 
    } 
} 

let john = Person.john() // I could also create a static property instead, but its a matter of personal choice and situation. 

ऊपर मामले में, मैं भी वैश्विक समारोह के रूप में john कर सकता था लेकिन मेरे लिए, यह बहुत अस्पष्ट है और पठनीय नहीं होगा।

एक और जगह मैं सोच सकता हूं कि जहां मैं स्थैतिक विधि पसंद करता हूं, enum के मामलों की गिनती वापस कर रहा है।

enum Mood { 
    case happy 
    case angry 
    case lazy 
    case high 

    static func count() -> Int { 
     return 4 
    } 
} 

ऐसे स्थान हैं, जहां मैं वैश्विक कार्यों का उपयोग करता हूं। मैं लॉगिंग के लिए वैश्विक कार्यों का उपयोग करता हूं।

func log(screenEvent name: String) { 
    let tracker = GAI.sharedInstance().defaultTracker 
    tracker.set(kGAIScreenName, value: screenName) 
    let builder = GAIDictionaryBuilder.createScreenView() 
    tracker.send(builder.build() as [NSObject : AnyObject]) 
} 

आंतरिक रूप से, विधि एक sharedInstance उपयोग कर रहा है, एक वैश्विक विधि बनाने यह आसानी से सिर्फ एक print समारोह जो कंसोल में उत्पादन लॉग की तरह इस परियोजना में हर जगह सुलभ बना देता है, लेकिन यह कुछ कस्टम सेवा में प्रवेश करने के है।

कुछ अन्य वैश्विक कार्य जिन्हें मैं आमतौर पर अपनी परियोजनाओं में शामिल करता हूं वे जीसीडी सहायक हैं।

func delay(delay:Double, closure: dispatch_block_t) { 
    dispatch_after(
     dispatch_time(
      DISPATCH_TIME_NOW, 
      Int64(delay * Double(NSEC_PER_SEC)) 
     ), 
     dispatch_get_main_queue(), closure) 
} 


func backgroundTask(closure: dispatch_block_t) { 
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), closure) 
} 

func mainThreadTask(closure: dispatch_block_t) { 
    dispatch_async(dispatch_get_main_queue(), closure) 
} 

इन कार्यों को कक्षा के बारे में किसी भी जानकारी की आवश्यकता नहीं है, इसलिए उन्हें कक्षा के अंदर लपेटने के बजाय उन्हें वैश्विक बनाने के लिए समझ में आता है।

instance विधियों के बारे में, जैसा कि @ डंकन सी द्वारा उत्तर दिया गया है, जब आप एक राज्य को बनाए रखना चाहते हैं तो उन्हें उदाहरणों पर बुलाया जाता है। उदाहरण के नीचे स्थिर और आवृत्ति विधियों दोनों का उपयोग दिखाता है।

enum TapType { 
    case water 
    case beer 
} 

struct Tap { 
    let tapType: TapType 

    //static method 
    static func unlimitedBeer() -> Tap { 
     let beer = Tap(tapType: .beer) 
     beer.turnOn(forDuration: Float.greatestFiniteMagnitude) 
     return beer 
    } 

    //instance method: will do operation on a particular instance of `Tap`. 
    func turnOn(forDuration duration: Float) { 
     //implementation 
    } 
} 

let unlimitedBeer = Tap.unlimitedBeer() 

तुम हमेशा कस्टम व्यवहार के साथ एक वस्तु initilise को convenience initiliser उपयोग कर सकते हैं, लेकिन फिर से, पसंद का अपना एक मामले। उपरोक्त उदाहरण में, मैं convenience initlialiser के बारे में नहीं सोच सकता था जो मुझे असीमित बियर देगा।

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