অন্য ক্লাসের ক্লাসক্লেকশন তৈরি করা কি ভাল অনুশীলন?


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>? বিশেষ করে দেওয়া হয়েছে যে কারকলিকেশন ব্যাকিং লিস্টের ক্লাসটি বাড়ায় না, বা এমনকি কালেকশন ইন্টারফেসটি বাস্তবায়ন করে না (আমি নিশ্চিত যে সি # তে একই জিনিস রয়েছে)।

তালিকা <T> ইতিমধ্যে IList <T>, আইকোলিকেশন <T>, আইলিস্ট, আইকোলিকেশন, আইআরএডলিলিস্ট <T>, আইআরইডঅনলিকেশন <টি>, আইএনওমারেবল <টি> এবং আইনিউবারেবল প্রয়োগ করেছে ... তাছাড়া আমি লিনক ব্যবহার করতে পারি ...
লুইস

তবে public class CarCollectionআইলিস্ট বা আইকোলিকেশন ইত্যাদি বাস্তবায়ন করে না ... সুতরাং আপনি এটি কোনও তালিকার সাথে ঠিক আছে এমন কিছুতে প্রেরণ করতে পারবেন না। এটি এর নামের অংশ হিসাবে দাবি করে যে এটি একটি সংগ্রহ, তবে এই পদ্ধতিগুলির কোনও প্রয়োগ করে না।

1
6 বছরের পুরানো প্রশ্ন হওয়ায় আমি দেখতে পাচ্ছি যে কেউ ডিডিডিতে এটি একটি সাধারণ অনুশীলন বলে উল্লেখ করেনি। যে কোনও সংগ্রহকে কাস্টম সংকলনে বিমূর্ত করা উচিত। উদাহরণস্বরূপ বলুন যে আপনি একটি দলের গাড়ির মূল্য গণনা করতে চেয়েছিলেন। কোথায় আপনি এই যুক্তি রাখবেন? একটি পরিষেবা? অথবা ডিডিডিতে আপনার CarColectionএকটি TotalTradeValueসম্পত্তি থাকবে। সিস্টেম ডিজাইন করার একমাত্র উপায় ডিডিডি নয়, কেবল এটি বিকল্প হিসাবে চিহ্নিত করা।
ঝড় মুলার

1
ঠিক যেমন, ডিডিডি-র পরামর্শ অনুসারে এই জিনিসগুলি প্রকৃতপক্ষে সমষ্টিগত শিকড়, কেবলমাত্র ডিডিডি সম্ভবত এটি আপনাকে গাড়ি সংগ্রহ বলার পরামর্শ দিবে না। বরং কিছু নাম যেমন পার্কিং লট, বা কাজের ক্ষেত্র ইত্যাদি ব্যবহার করুন
কোড নেম জ্যাক

উত্তর:


40

.NET এ জেনেরিক্সের আগে, 'টাইপড' সংগ্রহগুলি তৈরি করা সাধারণ অভ্যাস ছিল যাতে আপনার class CarCollectionগোষ্ঠীভুক্ত হওয়ার জন্য প্রয়োজনীয় প্রতিটি ধরণের জন্য আপনি ইত্যাদি রাখতে পারেন । জেনেরিক্স প্রবর্তনের সাথে .NET 2.0 এ, একটি নতুন ক্লাস List<T>চালু করা হয়েছিল যা আপনাকে তৈরি করতে পারে CarCollectionইত্যাদি তৈরির জন্য সংরক্ষণ করে List<Car>

বেশিরভাগ সময়, আপনি এটি List<T>আপনার লক্ষ্যের জন্য যথেষ্ট বলে খুঁজে পাবেন , তবে আপনার সংগ্রহে আপনি নির্দিষ্ট আচরণ করতে চান এমন অনেক সময় থাকতে পারে, যদি আপনি এটির বিষয়টি বিশ্বাস করেন, আপনার কাছে কয়েকটি বিকল্প রয়েছে:

  • List<T>উদাহরণস্বরূপ encapsulates যা একটি বর্গ তৈরি করুন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>
  • আপনি সংগ্রহ থেকে কোনও আইটেম যুক্ত করার বা অপসারণ করার পরে আপনি অতিরিক্ত ক্রিয়া সম্পাদন করতে চান

এটা কি ভাল অনুশীলন? ভাল এটি নির্ভর করে যে আপনি এটি করছেন কেন , যদি এটি উদাহরণস্বরূপ যদি আমি উপরে তালিকাভুক্ত করেছি কারণগুলির মধ্যে একটি হয় তবে হ্যাঁ।

মাইক্রোসফ্ট এটি নিয়মিত করে, এখানে বেশ কয়েকটি সাম্প্রতিক উদাহরণ রয়েছে:

আপনার 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ইত্যাদি ঘোষণা করা হয়েছে সেখানে মূলত যুক্তির সন্ধানের বিষয়ে যত্নশীল হতে পারেন না , এটি কেবলমাত্র ইউআই ক্রিয়াকলাপ হতে পারে।
ট্রেভর পিলি

এমএসডিএন-এর একটি নোট হিসাবে: "আমরা আপনাকে নতুন বিকাশের জন্য কালেকশনবেস ক্লাসটি ব্যবহার করার প্রস্তাব দিই না Instead পরিবর্তে, আমরা আপনাকে জেনেরিক সংগ্রহ <টি> ক্লাস ব্যবহার করার পরামর্শ দিই।" - ডকস.মাইক্রোসফট.ইন- ইউএস
রায়ান

9

নং XXXCollection.০.০ তে জেনেরিক্সের আবির্ভাবের সাথে ক্লাস তৈরির রীতিটি বেশ স্টাইলের বাইরে চলে গেছে। প্রকৃতপক্ষে, নিফটি Cast<T>()লিনকিউ এক্সটেনশন রয়েছে যা লোকেরা এই কাস্টম ফর্ম্যাটগুলি থেকে জিনিসগুলি বের করতে এই দিনগুলি ব্যবহার করে।


1
আমরা যে কাস্টম পদ্ধতিতে থাকতে পারি সে সম্পর্কে কী বলা যায় ClassCollection? এগুলি মুখ্য করে রাখা কি ভাল অনুশীলন Class?
লুইস

3
আমি বিশ্বাস করি যে এটি "নির্ভর করে" এর সফ্টওয়্যার বিকাশ মন্ত্রের আওতায় পড়ে। আপনি যদি উদাহরণস্বরূপ, আপনার FindCarByModelপদ্ধতি সম্পর্কে কথা বলছেন তবে এটি আপনার সংগ্রহস্থলের একটি পদ্ধতি হিসাবে বোধগম্য হয় যা কেবলমাত্র Carসংগ্রহের চেয়ে সামান্য জটিল ।
জেসি সি স্লিকার

2

উপরের ফাইন্ডবাইকারমোডেলের উদাহরণ অনুসারে, সংগ্রহ / স্লাইস সংগ্রহগুলি সন্ধান করার জন্য ডোমেন-ভিত্তিক পদ্ধতিগুলি প্রায়শই ব্যবহার করা সহজ, তবে মোড়ক সংগ্রহের ক্লাস তৈরির কোনও উপায় নেই। এই পরিস্থিতিতে আমি এখন সাধারণত এক্সটেনশন পদ্ধতির একটি সেট তৈরি করব।

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>ইত্যাদি

যেহেতু আমাদের অধ্যবসায় সমাধানটির একটি লিনকিউ সরবরাহকারী রয়েছে, তাই আমি প্রায়শই একই রকম ফিল্টার পদ্ধতি তৈরি করব যা চালিত হয় এবং ফিরে আসে IQueryable<T>, তাই আমরা এই অপারেশনগুলিও সংগ্রহস্থলটিতে প্রয়োগ করতে পারি।

.NET (ভাল, সি #) এর আইডিয়োম 1.1 সাল থেকে অনেক পরিবর্তন হয়েছে। কাস্টম সংগ্রহের ক্লাসগুলি বজায় রাখা একটি ব্যথা এবং আপনার CollectionBase<T>যদি প্রয়োজন সমস্ত কিছু ডোমেইন-নির্দিষ্ট ফিল্টার এবং নির্বাচক পদ্ধতিগুলি হয় তবে আপনি এক্সটেনশন পদ্ধতির সমাধানটি না পেয়ে উত্তরাধিকার সূত্রে সামান্যই লাভ করতে পারেন।


1

আমি মনে করি যে অন্যান্য আইটেমের সংগ্রহের জন্য বিশেষ শ্রেণি তৈরির একমাত্র কারণ হ'ল যখন আপনি এর কোনও মূল্যবোধ যুক্ত করেন, তখন কেবল উদাহরণস্বরূপ IListবা অন্য কোনও সংকলনের সংগ্রহ থেকে encapsulate / উত্তরাধিকারের চেয়ে আরও বেশি কিছু ।

উদাহরণস্বরূপ, আপনার ক্ষেত্রে, এমন একটি ক্রিয়াকলাপ যুক্ত করা যা এমনকি গাড়ী / এমনকি অসম স্থানে পার্ক করা গাড়িগুলির সাবলিস্টগুলি ফিরিয়ে আনবে ... এবং তারপরেও ... সম্ভবত এটি কেবল পুনরায় ব্যবহার করা হয়, কারণ যদি এটি কেবল একটি সুন্দর লিনকিউ সহ একটি লাইন নেয় ফাংশন এবং শুধুমাত্র একবার ব্যবহার করা হয়, মূলত কী? চুম্বন !

এখন, আপনি যদি অনেকগুলি বাছাই / সন্ধানের পদ্ধতিগুলি অফার করার পরিকল্পনা করেন, তবে হ্যাঁ, আমি মনে করি এটি কার্যকর হতে পারে কারণ এই বিশেষ সংগ্রহশ্রেণীতে এটিই তাদের অন্তর্ভুক্ত হওয়া উচিত। কিছু "অনুসন্ধান" অনুসন্ধানের জটিলতা বা বাছাই / অনুসন্ধান পদ্ধতিতে আপনি যা কিছু করতে পারেন তা "লুকিয়ে রাখার" জন্য এটি একটি ভাল উপায়।


এমনকি, আমি মনে করি আমি এই পদ্ধতিগুলিকে মূলত অন্তর্ভুক্ত করতে পারিClass
লুইস

হ্যাঁ, প্রকৃতপক্ষে ... আপনি পারবেন
জালান

-1

আমি নিম্নলিখিত বিকল্পের সাথে যেতে পছন্দ করি, যাতে আপনি সংগ্রহের পদ্ধতিটি যুক্ত করতে পারেন এবং তালিকার সুবিধাটি ব্যবহার করতে পারেন।

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

এবং তারপরে আপনি এটি সি # 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
}

- জেনেরিক সংস্করণ @ ব্রায়ান মন্তব্যের জন্য ধন্যবাদ

   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 আপনি এখনও এটা করেনি তালিকা <টি> থেকে উত্তরাধিকারী না stackoverflow.com/questions/21692193/why-not-inherit-from-listt
ব্রায়ান Boettcher

@ ব্রায়ান: আপনি যদি আপনার লিঙ্কটি পড়েন তবে এটি কখন গ্রহণযোগ্য? আপনি যখন এমন একটি প্রক্রিয়া তৈরি করছেন যা তালিকার <T> মেকানিজম প্রসারিত করে। , সুতরাং যতক্ষণ না কোনও অতিরিক্ত সম্পত্তি থাকবে ততক্ষণ তা ঠিক থাকবে
ওয়ালিদ একে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.