Ayo bilang aku ada Car
kelas:
public class Car
{
public string Engine { get; set; }
public string Seat { get; set; }
public string Tires { get; set; }
}
Katakanlah kita membuat sistem tentang tempat parkir, saya akan menggunakan banyak Car
kelas, jadi kami membuat CarCollection
kelas, mungkin ada beberapa metode tambahan seperti FindCarByModel
:
public class CarCollection
{
public List<Car> Cars { get; set; }
public Car FindCarByModel(string model)
{
// code here
return new Car();
}
}
Jika saya membuat kelas ParkingLot
, apa praktik terbaik?
Pilihan 1:
public class ParkingLot
{
public List<Car> Cars { get; set; }
//some other properties
}
Pilihan 2:
public class ParkingLot
{
public CarCollection Cars { get; set; }
//some other properties
}
Apakah ini merupakan praktik yang baik untuk menciptakan yang ClassCollection
lain Class
?
CarCollection
daripadaList<Car>
sekitar? Terutama mengingat bahwa CarCollection tidak memperpanjang kelas Daftar backing, atau bahkan mengimplementasikan antarmuka Koleksi (saya yakin bahwa C # memiliki hal serupa).public class CarCollection
tidak menerapkan IList atau ICollection, dll ... sehingga Anda tidak dapat meneruskannya ke sesuatu yang ok dengan daftar. Ia mengklaim sebagai bagian dari namanya bahwa itu adalah koleksi, tetapi tidak menerapkan metode-metode tersebut.CarColection
denganTotalTradeValue
properti di atasnya. DDD bukan satu-satunya cara untuk merancang sistem, hanya menunjukkannya sebagai opsi.Jawaban:
Sebelum obat generik di .NET, sudah menjadi praktik umum untuk membuat koleksi 'diketik' sehingga Anda akan memiliki
class CarCollection
dll untuk setiap jenis yang Anda butuhkan untuk dikelompokkan. Dalam. NET 2.0 dengan pengenalan Generics, sebuah kelas baruList<T>
diperkenalkan yang menghemat Anda harus membuatCarCollection
dll seperti yang Anda bisa buatList<Car>
.Sebagian besar waktu, Anda akan menemukan bahwa
List<T>
itu cukup untuk tujuan Anda, namun mungkin ada saat-saat Anda ingin memiliki perilaku tertentu dalam koleksi Anda, jika Anda yakin ini yang terjadi, Anda memiliki beberapa pilihan:List<T>
misalnyapublic class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
public class CarCollection : CollectionBase<Car> {}
Jika Anda menggunakan pendekatan enkapsulasi, Anda harus setidaknya mengekspos pencacah sehingga Anda akan mendeklarasikannya sebagai berikut:
Tanpa melakukan itu, Anda tidak dapat melakukan
foreach
over koleksi.Beberapa alasan Anda mungkin ingin membuat koleksi khusus adalah:
IList<T>
atauICollection<T>
Apakah ini praktik yang baik? baik itu tergantung pada mengapa Anda melakukannya, jika itu misalnya salah satu alasan saya sebutkan di atas maka ya.
Microsoft melakukannya dengan cukup teratur, berikut adalah beberapa contoh yang cukup baru:
Adapun
FindBy
metode Anda , saya akan tergoda untuk memasukkannya dalam metode ekstensi sehingga mereka dapat digunakan terhadap koleksi yang berisi mobil:Ini memisahkan kekhawatiran untuk menanyakan koleksi dari kelas yang menyimpan mobil.
sumber
ClassCollection
bahkan untuk menambah, menghapus, memperbarui metode, dengan menambahkan yang baruCarCRUD
yang akan merangkum semua metode ini ...CarCRUD
ekstensi karena menegakkan penggunaannya akan sulit, keuntungan untuk menempatkan logika crud kustom di kelas koleksi adalah bahwa tidak ada cara untuk memotongnya. Selain itu, Anda mungkin tidak benar-benar peduli tentang logika Temukan di perakitan inti tempatCar
dll dideklarasikan, yang mungkin hanya aktivitas UI.Tidak. Pembuatan
XXXCollection
kelas tidak lagi sesuai gaya dengan munculnya obat generik di .NET 2.0. Bahkan, adaCast<T>()
ekstensi LINQ bagus yang digunakan orang hari ini untuk mendapatkan hal-hal dari format kustom tersebut.sumber
ClassCollection
? apakah itu praktik yang baik untuk menempatkan mereka pada yang utamaClass
?FindCarByModel
metode Anda , itu masuk akal sebagai metode pada repositori Anda, yang sedikit lebih kompleks daripada sekadarCar
koleksi.Seringkali berguna untuk memiliki metode berorientasi domain untuk menemukan / mengiris koleksi, seperti pada contoh FindByCarModel di atas, tetapi tidak perlu menggunakan resor untuk membuat kelas koleksi pembungkus. Dalam situasi ini saya sekarang biasanya akan membuat satu set metode ekstensi.
Anda menambahkan sebanyak mungkin metode filter atau utilitas ke kelas yang Anda inginkan, dan Anda dapat menggunakannya di mana saja
IEnumerable<Car>
, termasuk apa sajaICollection<Car>
, arrayCar
,IList<Car>
dll.Karena solusi kegigihan kami memiliki penyedia LINQ, saya akan sering juga membuat metode filter serupa yang beroperasi dan kembali
IQueryable<T>
, sehingga kami dapat menerapkan operasi ini ke repositori juga.Ungkapan .NET (well, C #) telah banyak berubah sejak 1.1. Mempertahankan kelas koleksi khusus adalah hal yang menyusahkan, dan Anda mendapatkan sedikit dari mewarisi dari
CollectionBase<T>
yang tidak Anda dapatkan dengan solusi metode ekstensi jika semua yang Anda butuhkan adalah metode filter dan pemilih khusus domain.sumber
Saya pikir satu-satunya alasan untuk membuat kelas khusus untuk menyimpan koleksi item lain adalah ketika Anda menambahkan sesuatu yang bernilai padanya, sesuatu yang lebih dari sekedar merangkum / mewarisi dari instance
IList
atau jenis koleksi lainnya.Sebagai contoh, dalam kasus Anda, menambahkan fungsi yang akan mengembalikan sublists mobil yang diparkir di ruang genap / tidak rata ... Dan bahkan kemudian ... mungkin hanya jika itu sering digunakan kembali, karena jika hanya membutuhkan satu baris dengan LinQ yang bagus berfungsi dan hanya digunakan sekali, apa gunanya? KISS !
Sekarang, jika Anda berencana untuk menawarkan banyak metode penyortiran / pencarian, maka ya, saya pikir ini bisa berguna karena ini adalah tempat mereka seharusnya berada, di kelas koleksi khusus. Ini juga merupakan cara yang baik untuk "menyembunyikan" kerumitan beberapa pertanyaan "temukan" atau apa pun yang dapat Anda lakukan dengan metode penyortiran / pencarian.
sumber
Class
Saya lebih suka menggunakan opsi berikut, sehingga Anda dapat menambahkan metode Anda ke koleksi dan menggunakan keunggulan daftar.
dan kemudian Anda dapat menggunakannya seperti C # 7.0
Atau Anda bisa menggunakannya seperti
- Versi generik berkat komentar @Bryan
dan kemudian Anda bisa menggunakannya
sumber