क्या यह बुरा अभ्यास है कि नियंत्रक सेवा के बजाय रिपॉजिटरी कहता है?


43

क्या यह बुरा अभ्यास है कि नियंत्रक सेवा के बजाय रिपॉजिटरी कहता है?

अधिक समझाने के लिए:

मुझे पता है कि अच्छे डिजाइन कंट्रोलर कॉल सर्विस और सर्विस रिपॉजिटरी का इस्तेमाल करते हैं।

लेकिन कभी-कभी नियंत्रक में मुझे किसी भी तर्क की आवश्यकता नहीं होती है और बस डीबी से लाने और देखने के लिए इसे पास करने की आवश्यकता होती है।

और मैं इसे केवल रिपॉजिटरी कहकर कर सकता हूं - सेवा को कॉल करने की आवश्यकता नहीं है - क्या यह बुरा अभ्यास है?


आप सेवा को कैसे बुला रहे हैं? REST इंटरफ़ेस के माध्यम से?
रॉबर्ट हार्वे

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

3
भावहीन। यदि यह एक छोटा अनुप्रयोग है और आप केवल डेटाबेस से डेटा प्राप्त करने का प्रयास कर रहे हैं, तो एक सेवा परत तब तक बेकार है जब तक कि सेवा परत कुछ सार्वजनिक एपीआई जैसे कि REST इंटरफ़ेस का हिस्सा न हो। "क्या दूध आपके लिए अच्छा है या आपके लिए बुरा है?" आप लैक्टोज असहिष्णु हैं पर निर्भर करता है।
रॉबर्ट हार्वे

4
एक कठिन और तेज़ नियम नहीं है कि आपके पास नियंत्रक -> सेवा -> नियंत्रक पर रिपॉजिटरी संरचना -> रिपॉजिटरी होनी चाहिए। सही आवेदन के लिए सही पैटर्न चुनें। मैं क्या कहूंगा कि आपको अपने आवेदन को सुसंगत बनाना चाहिए।
निकोलाईडेंट

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

जवाबों:


32

नहीं, इसे इस तरह से सोचें: एक रिपॉजिटरी एक सेवा (भी) है।

यदि आप जिन संस्थाओं को रिपॉजिटरी हैंडल के माध्यम से प्राप्त करते हैं, तो अधिकांश व्यापारिक तर्क को संभालते हैं, अन्य सेवाओं की कोई आवश्यकता नहीं है। बस रिपॉजिटरी का होना ही काफी है।

यहां तक ​​कि अगर आपके पास कुछ सेवाएं हैं जिन्हें आपको अपनी संस्थाओं में हेरफेर करने के लिए गुजरना होगा। पहले रिपॉजिटरी से इकाई को पकड़ो और फिर इसे उक्त सेवा में पास करें। कोशिश करने से पहले ही HTTP 404 को टॉस करना बहुत सुविधाजनक है।

इसके अलावा पढ़ने के परिदृश्य के लिए यह आम है कि आपको बस एक DTO / ViewModel को प्रोजेक्ट करने के लिए इकाई की आवश्यकता होगी। बीच में एक सर्विस लेयर होने के कारण अक्सर कई तरीकों से गुजरता है जो कि बदसूरत है।


2
खूब कहा है! मेरी प्राथमिकता रिपॉजिटरी को कॉल करना है, और केवल मामलों में, फिर एक रिपॉजिटरी पर्याप्त नहीं है (यानी दो संस्थाओं को अलग-अलग रिपॉजिटरी का उपयोग करके संशोधित किया जाना चाहिए), मैं एक सेवा बनाता हूं जो इस ऑपरेशन के लिए जिम्मेदार है और इसे नियंत्रक से कॉल करता है।
ज़िगिमांतास

मेरे पास एक सेवा के उपयोग को सही ठहराने के लिए एक जटिल कोड था।
अबूझ

इसलिए मेरी रिपॉजिटरी 'व्यावसायिक वस्तुओं' की एक सूची लौटाती है, जिसे मुझे 'xml ऑब्जेक्ट्स' में बदलने की आवश्यकता है, क्या यह कारण सेवा परत के लिए पर्याप्त है? मैं प्रत्येक वस्तु पर एक विधि को दूसरे प्रकार में बदलने और एक नई सूची में जोड़ने का आह्वान कर रहा हूं।
bot_bot

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

4

नियंत्रक के लिए एक रिपॉजिटरी को सीधे कॉल करना बुरा नहीं है। एक "सेवा" सिर्फ एक और उपकरण है, इसलिए इसका उपयोग करें जहां यह समझ में आता है।

निकोलाईडेंट ने टिप्पणी की:

... सही आवेदन के लिए सही पैटर्न चुनें। मैं क्या कहूंगा कि आपको अपने आवेदन को सुसंगत बनाना चाहिए।

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

चिंताओं और परीक्षण की अच्छी पृथक्करण को बढ़ावा देने के लिए, रिपॉजिटरी एक निर्भरता होनी चाहिए जिसे आप एक निर्माता के माध्यम से सेवा में इंजेक्ट करते हैं:

IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);

service.DoSomething(...);

यदि डेटाबेस में रिकॉर्ड की खोज करने के लिए किसी प्रकार के मानकीकृत क्वेरी की आवश्यकता होती है, तो सेवा वर्ग आपके दृश्य मॉडल में लेने और फिर रिपॉजिटरी द्वारा निष्पादित क्वेरी का निर्माण करने के लिए एक अच्छी जगह हो सकती है।

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

विपरीत दिशा में जा रहे हैं, यदि आपके नियंत्रक को इसकी आईडी द्वारा एक रिकॉर्ड प्राप्त करने की आवश्यकता है, तो इसके लिए एक सेवा ऑब्जेक्ट को सौंपना एक स्लेजहेमर के साथ एक थंबटैक को मारने की तरह है - यह आपकी ज़रूरत से अधिक तरीका है।

मैंने पाया है कि लेन-देन, या कार्य वस्तु की एक इकाई को संभालने के लिए नियंत्रक सबसे अच्छी स्थिति में है । नियंत्रक या यूनिट ऑफ़ वर्क ऑब्जेक्ट तब जटिल परिचालनों के लिए सेवा वस्तुओं को सौंपता है, या सीधे सरल संचालन के लिए रिपॉजिटरी में जाता है (जैसे आईडी द्वारा रिकॉर्ड खोजना)।

public class ShoppingCartsController : Controller
{
    [HttpPost]
    public ActionResult Edit(int id, ShoppingCartForm model)
    {
        // Controller initiates a database session and transaction
        using (IStoreContext store = new StoreContext())
        {
            // Controller goes directly to a repository to find a record by Id
            ShoppingCart cart = store.ShoppingCarts.Find(id);

            // Controller creates the service, and passes the repository and/or
            // the current transaction
            ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);

            if (cart == null)
                return HttpNotFound();

            if (ModelState.IsValid)
            {
                // Controller delegates to a service object to manipulate the
                // Domain Model (ShoppingCart)
                service.UpdateShoppingCart(model, cart);

                // Controller decides to commit changes
                store.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }
    }
}

मुझे लगता है कि सेवाओं का मिश्रण और रिपॉजिटरी के साथ सीधे काम करना पूरी तरह स्वीकार्य है। यदि आपको आवश्यकता महसूस हुई तो आप कार्य की इकाई में लेनदेन को आगे बढ़ा सकते हैं।

जिम्मेदारियों का टूटना इस तरह होता है:

  • नियंत्रक अनुप्रयोग के प्रवाह को नियंत्रित करता है
    • अगर शॉपिंग कार्ट डेटाबेस में नहीं है तो "404 नहीं मिला"
    • सत्यापन विफल होने पर सत्यापन संदेशों के साथ फ़ॉर्म को फिर से प्रस्तुत करता है
    • खरीदारी की टोकरी बचाता है अगर सब कुछ बाहर की जाँच करता है
  • नियंत्रक आपके डोमेन मॉडल (या संस्थाओं) पर व्यावसायिक तर्क को निष्पादित करने के लिए एक सेवा वर्ग को दर्शाता है। सेवा वस्तुओं को व्यावसायिक तर्क को लागू नहीं करना चाहिए ! वे व्यापारिक तर्क को अंजाम देते हैं।
  • नियंत्रक सीधे संचालन के लिए रिपॉजिटरी में सीधे प्रतिनिधि रख सकते हैं
  • सेवा ऑब्जेक्ट दृश्य मॉडल में डेटा लेते हैं, और व्यावसायिक तर्क निष्पादित करने के लिए डोमेन मॉडल को सौंपते हैं (उदाहरण के लिए रिपॉजिटरी पर विधियों को कॉल करने से पहले डोमेन ऑब्जेक्ट पर सेवा ऑब्जेक्ट कॉल विधि)
  • सेवा वस्तुएँ डेटा दृढ़ता के लिए रिपॉजिटरी को सौंपती हैं
  • नियंत्रकों को या तो होना चाहिए:
    1. लेन-देन के जीवनकाल को प्रबंधित करें, या
    2. लेन-देन के जीवनकाल को प्रबंधित करने के लिए कार्य ऑब्जेक्ट की एक इकाई बनाएँ

1
रेपो के बजाय एक कंट्रोलर में DbContext डालने के लिए -1। रेपो डेटा प्रदाताओं को प्रबंधित करने के लिए है, इसलिए किसी और के पास डेटा प्रदाता परिवर्तन (उदाहरण के लिए MySQL से फ्लैट JSON फ़ाइलों में, एक स्थान पर परिवर्तन) के लिए नहीं है
जिमी हॉफ

@ जिमीहॉफ: मैं वास्तव में मेरे द्वारा लिखे गए कोड को देख रहा हूं, और ईमानदार होने के लिए, मैं अपने रिपॉजिटरी के लिए एक "संदर्भ" ऑब्जेक्ट बनाता हूं, डेटाबेस आवश्यक नहीं। मुझे लगता DbContextहै कि इस मामले में एक बुरा नाम है। मैं उसे बदल दूंगा। मैं NHibernate का उपयोग करता हूं, और रिपॉजिटरी (या यदि यह काम है तो संदर्भ) चीजों के डेटाबेस के अंत का प्रबंधन करता है, इसलिए दृढ़ता तंत्र को बदलने से संदर्भ के बाहर कोड परिवर्तन की आवश्यकता नहीं होती है।
ग्रेग बरगद्ट

आपको लगता है कि आपके कोड के अनुसार रिपॉजिटरी के साथ नियंत्रक भ्रमित हो रहा है ... मेरा मतलब है, आपका "संदर्भ" सभी गलत है और नियंत्रक में बिल्कुल मौजूद नहीं होना चाहिए।
जिमी होफा

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

1
एक रिपॉजिटरी, यह आमतौर पर सभी डेटा संदर्भ जानकारी के लिए ज़िम्मेदार होता है ताकि यह सुनिश्चित किया जा सके कि डेटा चिंताओं के बारे में और कुछ भी जानने की ज़रूरत नहीं है, इसके अलावा डोमेन को क्या जानना चाहिए
जिमी हॉफ

1

यह आपकी वास्तुकला पर निर्भर करता है। मैं स्प्रिंग का उपयोग करता हूं, और लेनदेन को हमेशा सेवाओं द्वारा प्रबंधित किया जाता है।

यदि आप रिपॉजिटरी को सीधे लिखने के संचालन के लिए कहते हैं (या बिना तर्क के सरल सेवाएं जो केवल रिपॉजिटरी को सौंपते हैं), तो शायद आप एक ऑपरेशन के लिए कई डेटाबेस लेनदेन का उपयोग कर रहे हैं जो एक में किया जाना चाहिए। यह आपके डेटाबेस में डेटा का नेतृत्व करेगा। एक सामान्य नियम के रूप में, डेटाबेस संचालन को काम करना चाहिए, या विफल होना चाहिए, लेकिन आधे-कार्य संचालन सिरदर्द का कारण हैं।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.