Saya pikir cara paling umum untuk menambahkan sesuatu ke koleksi adalah dengan menggunakan beberapa Add
metode yang disediakan oleh koleksi:
class Item {}
var items = new List<Item>();
items.Add(new Item());
dan sebenarnya tidak ada yang aneh tentang itu.
Namun saya heran mengapa kita tidak melakukannya dengan cara ini:
var item = new Item();
item.AddTo(items);
tampaknya lebih alami daripada metode pertama. Ini akan memiliki andantange bahwa ketika Item
kelas memiliki properti seperti Parent
:
class Item
{
public object Parent { get; private set; }
}
Anda dapat menjadikan setter pribadi. Dalam hal ini tentu saja Anda tidak dapat menggunakan metode ekstensi.
Tapi mungkin saya salah dan saya belum pernah melihat pola ini sebelumnya karena itu sangat jarang? Apakah Anda tahu ada pola seperti itu?
Dalam C#
suatu metode ekstensi akan berguna untuk itu
public static T AddTo(this T item, IList<T> list)
{
list.Add(item);
return item;
}
Bagaimana dengan bahasa lain? Saya kira sebagian besar dari mereka Item
harus menyediakan ICollectionItem
antarmuka , sebut saja antarmuka.
Perbarui-1
Saya telah memikirkannya sedikit lebih banyak dan pola ini akan sangat berguna misalnya jika Anda tidak ingin item ditambahkan ke beberapa koleksi.
ICollectable
antarmuka uji :
interface ICollectable<T>
{
// Gets a value indicating whether the item can be in multiple collections.
bool CanBeInMultipleCollections { get; }
// Gets a list of item's owners.
List<ICollection<T>> Owners { get; }
// Adds the item to a collection.
ICollectable<T> AddTo(ICollection<T> collection);
// Removes the item from a collection.
ICollectable<T> RemoveFrom(ICollection<T> collection);
// Checks if the item is in a collection.
bool IsIn(ICollection<T> collection);
}
dan contoh implementasi:
class NodeList : List<NodeList>, ICollectable<NodeList>
{
#region ICollectable implementation.
List<ICollection<NodeList>> owners = new List<ICollection<NodeList>>();
public bool CanBeInMultipleCollections
{
get { return false; }
}
public ICollectable<NodeList> AddTo(ICollection<NodeList> collection)
{
if (IsIn(collection))
{
throw new InvalidOperationException("Item already added.");
}
if (!CanBeInMultipleCollections)
{
bool isInAnotherCollection = owners.Count > 0;
if (isInAnotherCollection)
{
throw new InvalidOperationException("Item is already in another collection.");
}
}
collection.Add(this);
owners.Add(collection);
return this;
}
public ICollectable<NodeList> RemoveFrom(ICollection<NodeList> collection)
{
owners.Remove(collection);
collection.Remove(this);
return this;
}
public List<ICollection<NodeList>> Owners
{
get { return owners; }
}
public bool IsIn(ICollection<NodeList> collection)
{
return collection.Contains(this);
}
#endregion
}
pemakaian:
var rootNodeList1 = new NodeList();
var rootNodeList2 = new NodeList();
var subNodeList4 = new NodeList().AddTo(rootNodeList1);
// Let's move it to the other root node:
subNodeList4.RemoveFrom(rootNodeList1).AddTo(rootNodeList2);
// Let's try to add it to the first root node again...
// and it will throw an exception because it can be in only one collection at the same time.
subNodeList4.AddTo(rootNodeList1);
sumber
item.AddTo(items)
misalkan Anda memiliki bahasa tanpa metode ekstensi: alami atau tidak, untuk mendukung addTo, setiap jenis memerlukan metode ini dan menyediakannya untuk setiap jenis koleksi yang mendukung penambahan. Itu seperti contoh terbaik untuk memperkenalkan dependensi antara semua yang pernah saya dengar: P - Saya pikir premis yang salah di sini sedang mencoba untuk memodelkan beberapa abstraksi pemrograman ke kehidupan 'nyata'. Itu sering salah.add(item, collection)
, tapi itu bukan gaya OO yang baik.Jawaban:
Tidak,
item.AddTo(items)
itu tidak lebih alami. Saya pikir Anda mencampur ini dengan yang berikut:Anda benar karena
items.Add(item)
tidak terlalu dekat dengan bahasa Inggris alami. Tetapi Anda juga tidak mendengaritem.AddTo(items)
dalam bahasa Inggris alami, bukan? Biasanya ada seseorang yang seharusnya menambahkan item ke daftar. Baik itu ketika bekerja di supermarket atau saat memasak dan menambahkan bahan.Dalam hal bahasa pemrograman, kami membuatnya sehingga daftar melakukan keduanya: menyimpan barang-barangnya dan bertanggung jawab untuk menambahkannya ke dirinya sendiri.
Masalah dengan pendekatan Anda adalah bahwa item harus sadar bahwa ada daftar. Tapi sebuah item bisa ada walaupun tidak ada daftar sama sekali, kan? Ini menunjukkan bahwa ia seharusnya tidak mengetahui daftar. Daftar tidak boleh muncul dalam kodenya sama sekali.
Namun daftar tidak ada tanpa item (setidaknya mereka tidak akan berguna). Oleh karena itu tidak masalah jika mereka tahu tentang barang-barang mereka - setidaknya dalam bentuk generik.
sumber
@valenterry benar tentang masalah pemisahan masalah. Kelas seharusnya tidak tahu apa-apa tentang berbagai koleksi yang mungkin memuatnya. Anda tidak ingin harus mengubah kelas item setiap kali Anda membuat koleksi jenis baru.
Yang mengatakan ...
1. Bukan Java
Java tidak membantu Anda di sini, tetapi beberapa bahasa memiliki sintaksis yang lebih fleksibel dan dapat diperluas.
Di Scala, items.add (item) terlihat seperti ini:
Di mana :: adalah operator yang menambahkan item ke daftar. Sepertinya itu yang Anda inginkan. Ini sebenarnya adalah gula sintaksis
where :: adalah metode daftar Scala yang secara efektif setara dengan list.add Java . Jadi sementara itu terlihat di versi pertama seolah-olah item menambahkan dirinya sendiri ke item , sebenarnya item melakukan penambahan. Kedua versi tersebut adalah Scala yang valid
Trik ini dilakukan dalam dua langkah:
Jika Anda tidak nyaman dengan banyak operator dan menginginkan addTo Anda , Scala menawarkan opsi lain: konversi implisit. Ini membutuhkan dua langkah
Jika konversi implisit diaktifkan dan Scala melihat
atau
dan item tidak memiliki addTo , item akan mencari ruang lingkup saat ini untuk setiap fungsi konversi implisit. Jika salah satu fungsi konversi mengembalikan tipe yang memang memiliki metode addTo , ini terjadi:
Sekarang, Anda mungkin menemukan konversi implisit lebih sesuai dengan selera Anda, tetapi menambah bahaya, karena kode dapat melakukan hal-hal yang tidak terduga jika Anda tidak mengetahui dengan jelas semua konversi implisit dalam konteks tertentu. Inilah sebabnya mengapa fitur ini tidak lagi diaktifkan secara default di Scala. (Namun, sementara Anda dapat memilih untuk mengaktifkannya atau tidak dalam kode Anda sendiri, Anda tidak dapat melakukan apa-apa tentang statusnya di pustaka orang lain. Ini naga).
Operator yang diakhiri usus besar lebih buruk tetapi tidak menimbulkan ancaman.
Kedua pendekatan mempertahankan prinsip pemisahan keprihatinan. Anda dapat membuatnya terlihat seolah-olah barang yang tahu tentang koleksi, tetapi pekerjaan sebenarnya dilakukan di tempat lain. Bahasa lain apa pun yang ingin memberi Anda fitur ini harus setidaknya sama hati-hati.
2. Jawa
Di Jawa, di mana sintaksisnya tidak bisa diperluas oleh Anda, yang terbaik yang bisa Anda lakukan adalah membuat semacam kelas pembungkus / dekorator yang tahu tentang daftar. Di domain tempat item Anda ditempatkan dalam daftar, Anda bisa membungkusnya di dalamnya. Ketika mereka meninggalkan domain itu, keluarkan mereka. Mungkin pola pengunjung terdekat.
3. tl; dr
Scala, seperti beberapa bahasa lain, dapat membantu Anda dengan sintaksis yang lebih alami. Java hanya bisa menawarkan pola barok yang jelek.
sumber
Dengan metode ekstensi Anda, Anda masih harus memanggil Tambah () sehingga tidak menambahkan apa pun yang berguna untuk kode Anda. Kecuali jika metode addto Anda melakukan beberapa pemrosesan lain, tidak ada alasan untuk membuatnya ada. Dan menulis kode yang tidak memiliki tujuan fungsional buruk untuk keterbacaan dan pemeliharaan.
Jika Anda membiarkannya tidak umum, masalahnya menjadi lebih jelas. Anda sekarang memiliki item yang perlu diketahui tentang berbagai jenis koleksi yang ada. Itu melanggar prinsip tanggung jawab tunggal. Tidak hanya item pemegang untuk data itu, item ini juga memanipulasi koleksi. Itulah sebabnya kami meninggalkan tanggung jawab untuk menambahkan item ke koleksi hingga potongan kode yang memakan keduanya.
sumber
thing.giveTo(collection)
[dan mengharuskancollection
untuk menerapkan antarmuka "acceptOwnership"] akan lebih masuk akal daripadacollection
memasukkan metode yang merebut kepemilikan. Tentu saja ...Saya pikir Anda terobsesi dengan kata "tambah". Coba cari kata alternatif saja, seperti "kumpulkan", yang akan memberi Anda sintaks yang lebih ramah bahasa Inggris tanpa perubahan pola:
Metode di atas persis sama dengan
items.add(item);
, dengan satu-satunya perbedaan adalah pilihan kata yang berbeda, dan mengalir dengan sangat baik dan "alami" dalam bahasa Inggris.Terkadang, hanya penamaan ulang variabel, metode, kelas, dll. Akan mencegah perpajakan desain ulang pola.
sumber
collect
kadang-kadang digunakan sebagai nama untuk metode yang mengurangi koleksi item menjadi semacam hasil tunggal (yang juga bisa menjadi koleksi). Konvensi ini diadopsi oleh Java Steam API , yang membuat penggunaan nama dalam konteks ini sangat populer. Saya belum pernah melihat kata yang digunakan dalam konteks yang Anda sebutkan dalam jawaban Anda. Saya lebih suka tetap denganadd
atauput
push
atauenqueue
. Intinya bukan nama contoh spesifik, tetapi fakta bahwa nama yang berbeda mungkin lebih dekat dengan keinginan OP untuk tata bahasa Inggris-esque.Meskipun tidak ada pola seperti itu untuk kasus umum (seperti yang dijelaskan oleh orang lain), konteks di mana pola yang sama memiliki manfaatnya adalah asosiasi dua arah dua arah dalam ORM.
Dalam konteks ini Anda akan memiliki dua entitas, katakanlah
Parent
danChild
. Orang tua dapat memiliki banyak anak, tetapi setiap anak milik satu orang tua. Jika aplikasi mengharuskan asosiasi dapat dinavigasi dari kedua ujungnya (dua arah), Anda akan memilikiList<Child> children
di kelas induk danParent parent
di kelas anak.Asosiasi harus selalu bersifat timbal balik tentu saja. Solusi ORM biasanya memberlakukan ini pada entitas yang mereka muat. Tetapi ketika aplikasi memanipulasi entitas (baik yang bertahan atau yang baru), ia harus menegakkan aturan yang sama. Dalam pengalaman saya, Anda paling sering menemukan
Parent.addChild(child)
metode yang memanggilChild.setParent(parent)
, yang tidak untuk penggunaan umum. Dalam yang terakhir Anda biasanya akan menemukan cek yang sama seperti yang telah Anda terapkan dalam contoh Anda. Namun rute lain juga dapat diterapkan:Child.addTo(parent)
panggilan manaParent.addChild(child)
. Rute mana yang terbaik berbeda dari situasi ke situasi.sumber
Di Jawa, koleksi khas tidak memegang hal --Itu memegang referensi untuk hal-hal, atau lebih tepatnya salinan dari referensi untuk hal-hal. Sintaks dot-anggota, sebaliknya, umumnya digunakan untuk bertindak atas hal yang diidentifikasi oleh referensi, bukan pada referensi itu sendiri.
Sementara menempatkan apel dalam mangkuk akan mengubah beberapa aspek apel (misalnya lokasinya), menempatkan selembar kertas yang bertuliskan "objek # 29521" ke dalam mangkuk tidak akan mengubah apel dengan cara apa pun meskipun itu terjadi. objek # 29521. Lebih lanjut, karena koleksi menyimpan salinan referensi, tidak ada Jawa yang setara dengan menempatkan selembar kertas yang mengatakan "objek # 29521" ke dalam mangkuk. Sebagai gantinya, seseorang menyalin nomor # 29521 ke selembar kertas baru, dan menunjukkan (tidak memberikan) itu ke mangkuk, yang akan mereka buat salinannya sendiri, meninggalkan yang asli tidak terpengaruh.
Memang, karena referensi objek ("slip kertas") di Jawa dapat diamati secara pasif, baik referensi, maupun objek yang diidentifikasi, tidak memiliki cara untuk mengetahui apa yang sedang dilakukan dengan mereka. Ada beberapa jenis koleksi yang, alih-alih hanya memegang setumpuk referensi ke objek yang mungkin tidak tahu apa-apa tentang keberadaan koleksi, bukannya membangun hubungan dua arah dengan objek yang diringkas di dalamnya. Dengan beberapa koleksi seperti itu, mungkin masuk akal untuk meminta metode untuk menambahkan dirinya ke koleksi (terutama jika suatu objek hanya mampu berada di satu koleksi seperti itu pada suatu waktu). Namun, secara umum, sebagian besar koleksi tidak cocok dengan pola itu, dan dapat menerima referensi ke objek tanpa keterlibatan apa pun pada bagian objek yang diidentifikasi oleh referensi tersebut.
sumber
item.AddTo(items)
tidak digunakan karena pasif. Cf "Item ditambahkan ke daftar" dan "ruangan dilukis oleh dekorator".Konstruksi pasif baik-baik saja, tetapi, setidaknya dalam bahasa Inggris, kami cenderung lebih suka konstruksi aktif.
Dalam pemrograman OO, pardigmanya menonjol bagi aktor, bukan aktor yang ditindaklanjuti, jadi kami memilikinya
items.Add(item)
. Daftar adalah hal yang melakukan sesuatu. Ini adalah aktor, jadi ini adalah cara yang lebih alami.sumber
list.Add(item)
suatu item sedang ditambahkan ke daftar atau daftar menambahkan item atau tentangitem.AddTo(list)
item menambahkan dirinya ke daftar atau saya menambahkan item ke daftar atau seperti Anda telah mengatakan item ditambahkan ke daftar - semuanya benar. Jadi pertanyaannya adalah siapa aktornya dan mengapa? Item juga merupakan aktor dan ingin bergabung dengan grup (daftar) bukan grup yang ingin memiliki item ini ;-) item tersebut berperan aktif dalam grup.Parent
properti. Memang bahasa Inggris bukan bahasa asli tetapi sejauh yang saya tahu inginkan tidak pasif kecuali saya ingin atau dia ingin saya melakukan sesuatu ; -]List<T>
(setidaknya yang ditemukan diSystem.Collections.Generic
) tidak memperbaruiParent
properti sama sekali. Bagaimana mungkin, jika itu seharusnya generik? Biasanya tanggung jawab wadah untuk menambahkan isinya.