छोटे कार्य बनाम एक ही कार्य में निर्भर कार्यक्षमता रखते हुए


15

मेरे पास एक वर्ग है जो नोड्स की एक सरणी सेट करता है और उन्हें ग्राफ़-जैसी संरचना में एक दूसरे से जोड़ता है। क्या यह सबसे अच्छा है:

  1. किसी फ़ंक्शन को प्रारंभ करने और नोड्स को कनेक्ट करने के लिए कार्यक्षमता रखें
  2. दो अलग-अलग कार्यों में आरंभीकरण और कनेक्शन की कार्यक्षमता है (और एक आश्रित क्रम है, जिस पर फ़ंक्शन को बुलाया जाना चाहिए - हालांकि ध्यान रखें कि ये कार्य निजी हैं।)

विधि 1: (उस एक फ़ंक्शन में खराब दो काम कर रहा है, लेकिन यह निर्भरता कार्यक्षमता को एक साथ समूहीकृत करता है - नोड्स को पहले आरंभ किए बिना कभी भी जुड़ा नहीं होना चाहिए।)

init() {
    setupNodes()
}

private func setupNodes() {
    // 1. Create array of nodes
    // 2. Go through array, connecting each node to its neighbors 
    //    according to some predefined constants
}

विधि 2: (इस अर्थ में बेहतर है कि यह स्व-दस्तावेजीकरण है, लेकिन BUT कनेक्टनॉड्स () को सेटअपऑनोड्स () से पहले कभी नहीं बुलाया जाना चाहिए, इसलिए क्लास इंटर्नल के साथ काम करने वाले किसी व्यक्ति को इस आदेश के बारे में जानना होगा।)

init() {
    setupNodes()
}

private func setupNodes() {
    createNodes()
    connectNodes()
}

private func createNodes() {
    // 1. Create array of nodes
}

private func connectNodes() {
    // 2. Go through array, connecting each node to its neighbors 
    //    according to some predefined constants
}

कोई भी विचार सुनने के लिए उत्साहित।



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

जवाबों:


23

जिस समस्या से आप निपट रहे हैं उसे टेम्पोरल कपलिंग कहा जाता है

आप इस कोड के बारे में चिंतित होने के बारे में चिंतित हैं:

private func setupNodes() {
    createNodes();
    connectNodes();
}

मैं अनुमान लगा सकता हूं कि वहां क्या चल रहा है, लेकिन मुझे बताएं कि क्या इससे कुछ और स्पष्ट होता है?

private func setupNodes() {
    self.nodes = connectNodes( createNodes() );
}

यह उदाहरण चर को कम करने के लिए कम युग्मित होने का अतिरिक्त लाभ है, लेकिन मेरे लिए पठनीय होना नंबर एक है।

इससे connectNodes()नोड्स पर निर्भरता स्पष्ट हो जाती है।


1
लिंक के लिए धन्यवाद। चूंकि स्विफ्ट में मेरे कार्य निजी हैं और निर्माता से बुलाए गए हैं - init () - मुझे नहीं लगता कि मेरा कोड आपके द्वारा लिंक किए गए उदाहरणों जितना बुरा होगा (बाहरी ग्राहक के लिए एक उदाहरण के साथ इंस्टेंस को इंस्टेंट करना असंभव होगा अशक्त उदाहरण चर), लेकिन मुझे एक समान गंध है।
mcfroob

1
आपके द्वारा जोड़ा गया कोड अधिक पठनीय है, इसलिए मैं उस शैली में रिफ्लेक्टर करूंगा।
mcfroob

10

दो कारणों से अलग कार्य :

1. निजी कार्य इस स्थिति के लिए निजी हैं।

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

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

2. एक दूसरे से नोड कनेक्ट करना एक निजी कार्य नहीं हो सकता है

क्या होगा अगर किसी बिंदु पर आप सरणी में अन्य नोड्स जोड़ना चाहते हैं? क्या आपने अभी जो सेटअप किया है, उसे नष्ट कर दें और इसे पूरी तरह से फिर से शुरू करें? या क्या आप मौजूदा सरणी में नोड्स जोड़ते हैं और फिर फिर से चलाते हैं connectNodes?

connectNodesयदि नोड्स की सरणी अभी तक नहीं बनाई गई है, तो संभवत: एक प्रतिक्रिया हो सकती है (एक अपवाद फेंकें? एक खाली सेट लौटाएं? आपको तय करना होगा कि आपकी स्थिति के लिए क्या मायने रखता है)।


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

4

आप यह भी पा सकते हैं (इन कार्यों में से प्रत्येक कितना जटिल है पर निर्भर करता है) कि यह एक और वर्ग को विभाजित करने के लिए एक अच्छा सीम है।

(निश्चित नहीं कि स्विफ्ट इस तरह से काम करे लेकिन छद्म कोड :)

class YourClass {
    init(generator: NodesGenerator) {
        self.nodes = connectNodes(generator.make())
    }
    private func connectNodes() {

    }
}

class NodesGenerator {
    public func make() {
        // Return some nodes from storage or make new ones
    }
}

यह नोड्स को अलग-अलग वर्गों को बनाने और संशोधित करने की जिम्मेदारियों को अलग NodeGeneratorकरता है : केवल नोड्स बनाने / प्राप्त करने की YourClassपरवाह करता है , जबकि केवल नोड्स को जोड़ने के बारे में परवाह करता है।


2

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

इनर मेथड उन फंक्शन्स के लिए परफेक्ट होते हैं, जिनमें केवल एक ही कॉल साइट होती है, लेकिन ऐसा लगता है कि वे अलग-अलग प्राइवेट फंक्शन होने का औचित्य नहीं रखते।

उदाहरण के लिए, सार्वजनिक पुनरावर्ती "प्रवेश" फ़ंक्शन का होना बहुत आम है, जो पूर्व शर्त की जांच करता है, कुछ मापदंडों को सेट करता है, और एक निजी पुनरावर्ती कार्य को सौंपता है जो काम करता है।

यहाँ एक उदाहरण है कि इस मामले में कैसे दिख सकता है:

init() {
    self.nodes = setupNodes()

    func setupNodes() {
        var nodes = createNodes()
        connect(Nodes: nodes)
    }

    private func createNodes() -> [Node]{
        // 1. Create array of nodes
    }

    func connect(Nodes: [Node]) {
        // 2. Go through array, connecting each node to its neighbors 
        //    according to some predefined constants
    }
}

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


0

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

हालांकि अगर यह आपके प्रोग्राम के अन्य हिस्सों द्वारा उपयोग नहीं किया जाता है, तो मैं इसे एक अलग फ़ंक्शन के रूप में उजागर नहीं करूंगा।

यदि आपकी भाषा इसका समर्थन करती है, तो आप अभी भी नेस्टेड फ़ंक्शन का उपयोग करके एक-फ़ंक्शन-एक-एक कर सकते हैं

function setupNodes ()  {
  function createNodes ()  {...} 
  function connectNodes ()  {...}
  createNodes() 
  connectNodes() 
} 

घोषणा की जगह बहुत मायने रखती है, और ऊपर के उदाहरण में यह किसी भी अन्य सुराग की आवश्यकता के बिना स्पष्ट है कि आंतरिक कार्यों का उपयोग केवल बाहरी फ़ंक्शन के शरीर के भीतर किया जाना है।

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

मुझे नहीं लगता कि आपको कड़ाई से एक या दूसरे को करना होगा। केस के आधार पर किसी मामले में भिन्नता सबसे अच्छी होती है।

कई कार्यों में इसे तोड़ना निश्चित रूप से यह समझने का ओवरहेड जोड़ता है कि 3 फ़ंक्शन क्यों हैं और वे सभी एक दूसरे के साथ कैसे काम करते हैं, लेकिन यदि तर्क जटिल है, तो यह जोड़ा ओवरहेड जटिल तर्क को तोड़कर शुरू की गई सादगी से बहुत कम हो सकता है सरल भागों में।


दिलचस्प विकल्प। जैसा कि आप कहते हैं, मुझे लगता है कि यह थोड़ा अजीब हो सकता है कि क्यों इस तरह से समारोह घोषित किया गया था, लेकिन यह फ़ंक्शन निर्भरता को अच्छी तरह से रखेगा।
mcfroob

इस प्रश्न में कुछ अनिश्चितताओं का उत्तर देने के लिए: 1) हां, स्विफ्ट आंतरिक कार्यों का समर्थन करता है, और 2) इसके "निजी" स्तर दो हैं। privateकेवल एनक्लोजिंग प्रकार (स्ट्रक्चर / क्लास / एनम) के भीतर पहुंच की अनुमति देता है, जबकि fileprivateपूरी फाइल तक पहुंचने की अनुमति देता है
अलेक्जेंडर - मोनिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.