क्या किसी अन्य कक्षा का क्लासकॉलिनेशन बनाना एक अच्छा अभ्यास है?


35

आइए कहते हैं कि मेरे पास एक Carवर्ग है:

public class Car
{
    public string Engine { get; set; }
    public string Seat { get; set; }
    public string Tires { get; set; }
}

कहते हैं कि हम एक पार्किंग स्थल के बारे में एक प्रणाली बना रहे हैं, मैं बहुत सारे Carवर्ग का उपयोग करने जा रहा हूं , इसलिए हम एक CarCollectionवर्ग बनाते हैं , इसमें कुछ विशेषण विधियाँ हो सकती हैं जैसे FindCarByModel:

public class CarCollection
{
    public List<Car> Cars { get; set; }

    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

अगर मैं एक वर्ग बना रहा हूं ParkingLot, तो सबसे अच्छा अभ्यास क्या है?

विकल्प 1:

public class ParkingLot
{
    public List<Car> Cars { get; set; }
    //some other properties
}

विकल्प 2:

public class ParkingLot
{
    public CarCollection Cars { get; set; }
    //some other properties
}

यह भी एक बनाने के लिए एक अच्छा अभ्यास है ClassCollectionएक और की Class?


आसपास के CarCollectionबजाए पास करने में आपको क्या फायदा होता है List<Car>? विशेष रूप से यह देखते हुए कि CarCollection समर्थन सूची वर्ग का विस्तार नहीं करता है, या यहां तक ​​कि संग्रह इंटरफ़ेस भी लागू करता है (मुझे यकीन है कि C # में समान चीजें हैं)।

सूची <T> पहले से ही लागू करता है IList <T>, ICollection <T>, IList, ICollection, IReadOnlyList <T>, IReadOnlyCollection <T>, IEnumerer <T> और IEnumerable ... इसके अलावा, मैं Linq का उपयोग कर सकता हूं ...
लुइस

लेकिन public class CarCollectionIList या ICollection इत्यादि को लागू नहीं करता है ... इस प्रकार आप इसे किसी ऐसी चीज़ से पारित नहीं कर सकते जो किसी सूची के साथ ठीक है। यह अपने नाम के हिस्से के रूप में दावा करता है कि यह एक संग्रह है, लेकिन उन तरीकों में से कोई भी लागू नहीं करता है।

1
एक 6 साल पुराना प्रश्न होने के नाते मैं देख रहा हूं कि किसी ने उल्लेख नहीं किया है कि यह डीडीडी में एक आम बात है। किसी भी संग्रह को एक कस्टम संग्रह में सार किया जाना चाहिए। उदाहरण के लिए, आप कारों के एक समूह के मूल्य की गणना करना चाहते थे। आप उस तर्क को कहां रखेंगे? एक सेवा में या DDD में आप इस पर CarColectionएक TotalTradeValueसंपत्ति के साथ होगा। DDD सिस्टम को डिज़ाइन करने का एकमात्र तरीका नहीं है, बस इसे एक विकल्प के रूप में इंगित करता है।
स्टॉर्म मुलर

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

जवाबों:


40

.NET में जेनेरिक से पहले, 'टाइप' कलेक्शन बनाना आम बात थी class CarCollection समूह के लिए आवश्यक हर प्रकार के लिए आदि । .NET 2.0 में जेनरिक की शुरुआत के साथ, एक नया वर्ग List<T>पेश किया गया था जो आपको बनाने के लिए CarCollectionआदि की बचत करता है List<Car>

अधिकांश समय, आप पाएंगे कि List<T>यह आपके उद्देश्यों के लिए पर्याप्त है, हालांकि कई बार ऐसा भी हो सकता है कि आप अपने संग्रह में विशिष्ट व्यवहार करना चाहते हैं, यदि आप मानते हैं कि यह मामला है, तो आपके पास कुछ विकल्प हैं:

  • एक वर्ग बनाएं जो List<T>उदाहरण के लिए एनकैप्सुलेट करता हैpublic class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
  • एक कस्टम संग्रह बनाएँ public class CarCollection : CollectionBase<Car> {}

यदि आप एनकैप्सुलेशन दृष्टिकोण के लिए जाते हैं, तो आपको कम से कम प्रगणक को उजागर करना चाहिए ताकि आप इसे इस प्रकार घोषित करें:

public class CarCollection : IEnumerable<Car>
{
    private List<Car> cars = new List<Car>();

    public IEnumerator<Car> GetEnumerator() { return this.cars.GetEnumerator(); }
}

ऐसा किए बिना, आप ऐसा नहीं कर सकते foreach संग्रह से अधिक ।

कुछ कारण जिन्हें आप कस्टम संग्रह बनाना चाहते हैं, वे हैं:

  • आप पूरी तरह से सभी तरीकों को उजागर नहीं करना चाहते हैं IList<T> याICollection<T>
  • आप किसी आइटम को संग्रह से जोड़ने या निकालने पर अतिरिक्त कार्य करना चाहते हैं

क्या यह अच्छा अभ्यास है? अच्छी तरह से कि क्यों पर निर्भर करता है आप ऐसा कर रहे हैं, अगर यह उदाहरण के लिए एक कारण है जो मैंने ऊपर सूचीबद्ध किया है तो हाँ।

Microsoft इसे नियमित रूप से करते हैं, यहाँ कुछ हालिया उदाहरण हैं:

आपके FindByतरीकों के लिए, मुझे उन्हें विस्तार विधियों में लगाने का प्रलोभन दिया जाएगा ताकि उनका उपयोग कारों के किसी भी संग्रह के खिलाफ किया जा सके:

public static class CarLookupQueries
{
    public static Car FindByLicencePlate(this IEnumerable<Car> source, string licencePlate)
    {
        return source.SingleOrDefault(c => c.LicencePlate == licencePlate);
    }

    ...
}

यह कारों को संग्रहीत करने वाले वर्ग से संग्रह को क्वेरी करने की चिंता को अलग करता है।


इस दृष्टिकोण के बाद, मैं ClassCollectionऐड, डिलीट, अपडेट के तरीकों को भी खारिज कर सकता हूं , एक नया जोड़कर CarCRUDजो इस सभी तरीकों को पूरा करेगा ...
लुइस

@ मैं CarCRUDविस्तार की सिफारिश नहीं करूंगा क्योंकि इसके उपयोग को लागू करना मुश्किल होगा, कस्टम क्रूड लॉजिक को कलेक्शन क्लास में रखने का फायदा यह है कि इसे बाईपास करने का कोई तरीका नहीं है। इसके अतिरिक्त, आप वास्तव में कोर विधानसभा में लॉजिक लॉजिक के बारे में परवाह नहीं कर सकते Carहैं जहां आदि घोषित किए जाते हैं, यह एक यूआई केवल गतिविधि हो सकती है।
ट्रेवर पिली

MSDN से एक नोट के रूप में: "हम अनुशंसा नहीं करते हैं कि आप नए विकास के लिए CollectionBase वर्ग का उपयोग करें। इसके बजाय, हम अनुशंसा करते हैं कि आप सामान्य संग्रह <T> वर्ग का उपयोग करें।" - docs.microsoft.com/en-us/dotnet/api/…
रयान

9

नहीं। XXXCollectionनेट 2.0 में जेनेरिक के आगमन के साथ कक्षाओं का निर्माण बहुत शैली से बाहर हो गया। वास्तव में, निफ्टी Cast<T>()LINQ एक्सटेंशन है जो लोग इन दिनों का उपयोग उन कस्टम प्रारूपों से बाहर निकलने के लिए करते हैं।


1
उस कस्टम तरीकों के बारे में जो हमारे अंदर हो सकता है ClassCollection? उन्हें मुख्य पर रखना एक अच्छा अभ्यास है Class?
लुइस

3
मेरा मानना ​​है कि "यह निर्भर करता है" के सॉफ्टवेयर विकास मंत्र के अंतर्गत आता है। यदि आप के बारे में बात कर रहे हैं, उदाहरण के लिए, आपकी FindCarByModelविधि, जो आपके भंडार पर एक विधि के रूप में समझ में आता है, जो कि केवल एक Carसंग्रह की तुलना में थोड़ा अधिक जटिल है ।
जेसी सी। स्लीकर

2

जैसा कि FindByCarModel उदाहरण के ऊपर, संग्रह / खोजने / स्लाइस करने के लिए डोमेन-उन्मुख तरीकों को अक्सर करना आसान है, लेकिन रैपर संग्रह कक्षाएं बनाने के लिए सहारा लेने की आवश्यकता नहीं है। इस स्थिति में अब मैं आमतौर पर विस्तार विधियों का एक सेट बनाऊंगा।

public static class CarExtensions
{
    public static IEnumerable<Car> ByModel(this IEnumerable<Car> cars, string model)
    {
        return cars.Where(car => car.Model == model);
    }
}

आप उस वर्ग में जितने चाहें उतने फ़िल्टर या उपयोगिता विधियाँ जोड़ते हैं, और आप उन्हें कहीं भी उपयोग कर सकते हैं IEnumerable<Car>, जिसमें कुछ भी शामिल हैICollection<Car> , हो Car,IList<Car> आदि

चूँकि हमारे दृढ़ता समाधान में एक LINQ प्रदाता है, मैं अक्सर इसी तरह के फ़िल्टर तरीके बनाता हूँ जो चालू और वापस आते हैं IQueryable<T> , इसलिए हम इन ऑपरेशनों को रिपॉजिटरी में भी लागू कर सकते हैं।

.NET का आइडियल (वेल, C #) 1.1 से बहुत बदल गया है। कस्टम संग्रह कक्षाओं को बनाए रखना एक दर्द है, और CollectionBase<T>अगर आपको ज़रूरत है तो विस्तार विधि समाधान के साथ प्राप्त करने से आपको विरासत में बहुत कम हासिल होता है, यदि आपको डोमेन-विशिष्ट फ़िल्टर और चयनकर्ता विधियाँ चाहिए।


1

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

उदाहरण के लिए, आपके मामले में, एक ऐसा फंक्शन जोड़ना जो कारों की सब्लिस्ट को सम / असमान लॉट स्पेस पर पार्क किया जाएगा ... और तब भी ... शायद तभी जब इसका अक्सर उपयोग किया जाता है, क्योंकि अगर यह केवल एक लाइन के साथ अच्छा लाइनक्यू लेता है फ़ंक्शन और केवल एक बार उपयोग किया जाता है, क्या बात है? KISS !

अब, यदि आप बहुत सारे छंटाई / खोजने के तरीकों की पेशकश करने की योजना बना रहे हैं, तो हाँ, मुझे लगता है कि यह उपयोगी हो सकता है क्योंकि यह वह जगह है जहाँ उन्हें उस विशेष संग्रह वर्ग में होना चाहिए। यह कुछ "खोजने" की जटिलताओं को "छिपाने" के लिए भी एक अच्छा तरीका है, जो आप एक छँटाई / खोजने की विधि में कुछ भी कर सकते हैं।


यहां तक ​​कि मुझे लगता है कि मैं उन तरीकों को मुख्य रूप से शामिल कर सकता हूंClass
लुइस

हाँ, वास्तव में ... आप कर सकते हैं
जलयेन

-1

मैं निम्नलिखित विकल्प के साथ जाना पसंद करता हूं, इसलिए आप संग्रह में विधि जोड़ सकते हैं और सूची का लाभ उठा सकते हैं।

public class CarCollection:List<Car>
{
    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

और फिर आप इसे C # 7.0 की तरह उपयोग कर सकते हैं

public class ParkingLot
{
    public CarCollection Cars { get; set; }=new CarCollection();
    //some other properties
}

या आप इसका उपयोग कर सकते हैं

public class ParkingLot
{
   public ParkingLot()
   {
      //initial set
      Cars =new CarCollection();
   }
    public CarCollection Cars { get; set; }
    //some other properties
}

- सामान्य संस्करण @Bryan टिप्पणी के लिए धन्यवाद

   public class MyCollection<T>:List<T> where T:class,new()
    {
        public T FindOrNew(Predicate<T> predicate)
        {
            // code here
            return Find(predicate)?? new T();
        }
       //Other Common methods
     }

और फिर आप इसका उपयोग कर सकते हैं

public class ParkingLot
{
    public MyCollection<Car> Cars { get; set; }=new MyCollection<Car>();
    public MyCollection<Motor> Motors{ get; set; }=new MyCollection<Motor>();
    public MyCollection<Bike> Bikes{ get; set; }=new MyCollection<Bike>();
    //some other properties
}

सूची <टी> से प्राप्त न करें
ब्रायन बोएचर

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

1
@WaleedAK आपने अभी भी यह किया है - सूची <T> से प्राप्त न करें: stackoverflow.com/questions/21692193/why-not-inherit-from-listt
ब्रायन बोएटचर

@ ब्रायन: यदि आप अपना लिंक पढ़ते हैं तो यह कब स्वीकार्य है? जब आप एक तंत्र का निर्माण कर रहे हैं जो सूची <T> तंत्र का विस्तार करता है। , तो यह तब तक ठीक रहेगा जब तक कि कोई अतिरिक्त गुण न हों
एके
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.