Pertanyaan Mengapa tidak mewarisi dari List ?


Ketika merencanakan program saya, saya sering memulai dengan rantai pemikiran seperti ini:

Tim sepak bola hanyalah daftar pemain sepak bola. Oleh karena itu, saya harus mewakilinya dengan:

var football_team = new List<FootballPlayer>();

Urutan daftar ini mewakili urutan di mana pemain terdaftar dalam daftar.

Tetapi saya menyadari kemudian bahwa tim juga memiliki properti lain, selain daftar pemain belaka, yang harus direkam. Misalnya, total skor yang berjalan musim ini, anggaran saat ini, warna seragam, a string mewakili nama tim, dll.

Jadi saya pikir:

Oke, tim sepakbola sama seperti daftar pemain, tetapi selain itu, ia memiliki nama (a string) dan total skor yang berjalan (an int). .NET tidak menyediakan kelas untuk menyimpan tim sepak bola, jadi saya akan membuat kelas sendiri. Struktur yang paling mirip dan relevan adalah List<FootballPlayer>, jadi saya akan mewarisi darinya:

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

Tapi ternyata itu sebuah pedoman mengatakan Anda tidak harus mewarisi dari List<T>. Saya benar-benar bingung dengan panduan ini dalam dua hal.

Kenapa tidak?

Tampaknya List entah bagaimana dioptimalkan untuk kinerja. Bagaimana? Masalah kinerja apa yang akan saya timbulkan jika saya perpanjang List? Apa sebenarnya yang akan hancur?

Alasan lain yang pernah saya lihat adalah itu List disediakan oleh Microsoft, dan saya tidak punya kendali atas itu, jadi Saya tidak dapat mengubahnya nanti, setelah memaparkan "API publik". Tetapi saya berjuang untuk memahami ini. Apa itu API publik dan mengapa saya harus peduli? Jika proyek saya saat ini tidak dan tidak mungkin memiliki API publik ini, dapatkah saya mengabaikan panduan ini dengan aman? Jika saya mewarisi dari List  dan ternyata saya membutuhkan API publik, kesulitan apa yang akan saya miliki?

Mengapa itu penting? Daftar adalah daftar. Apa yang bisa berubah? Apa yang mungkin ingin saya ubah?

Dan terakhir, jika Microsoft tidak ingin saya mewarisinya List, kenapa mereka tidak masuk kelas sealed?

Apa lagi yang harus saya gunakan?

Rupanya, untuk koleksi kustom, Microsoft telah menyediakan Collection kelas yang harus diperpanjang bukan List. Tetapi kelas ini sangat kosong, dan tidak memiliki banyak hal yang bermanfaat, seperti AddRange, contohnya. jawaban jvitor83 memberikan alasan kinerja untuk metode tertentu, tetapi bagaimana lambat AddRange tidak lebih baik daripada tidak AddRange?

Mewarisi dari Collection jauh lebih pekerjaan daripada mewarisi dari List, dan saya tidak melihat manfaatnya. Tentunya Microsoft tidak akan memberitahu saya untuk melakukan pekerjaan tambahan tanpa alasan, jadi saya tidak bisa menahan perasaan seperti saya entah bagaimana salah paham sesuatu, dan mewarisi Collection sebenarnya bukan solusi yang tepat untuk masalah saya.

Saya telah melihat saran seperti menerapkan IList. Hanya tidak. Ini adalah lusinan baris kode boilerplate yang tidak memberi saya apa-apa.

Terakhir, beberapa menyarankan membungkus List dalam sesuatu:

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

Ada dua masalah dengan ini:

  1. Itu membuat kode saya tidak perlu bertele-tele. Saya sekarang harus menelepon my_team.Players.Count bukan hanya my_team.Count. Untungnya, dengan C # saya dapat mendefinisikan pengindeks untuk membuat pengindeksan transparan, dan meneruskan semua metode internal List... Tapi itu banyak kode! Apa yang saya dapatkan untuk semua pekerjaan itu?

  2. Itu tidak masuk akal. Tim sepak bola tidak "memiliki" daftar pemain. Saya t aku s daftar pemain. Anda tidak mengatakan "John McFootballer telah bergabung dengan pemain SomeTeam". Anda mengatakan "John telah bergabung dengan SomeTeam". Anda tidak menambahkan huruf ke "karakter string", Anda menambahkan huruf ke string. Anda tidak menambahkan buku ke buku perpustakaan, Anda menambahkan buku ke perpustakaan.

Saya menyadari bahwa apa yang terjadi "di bawah kap mesin" dapat dikatakan sebagai "menambahkan daftar internal X ke Y", tetapi ini tampaknya seperti cara berpikir yang sangat kontra-intuitif tentang dunia.

Pertanyaan saya (diringkas)

Apa cara C # yang benar untuk merepresentasikan struktur data, yang "secara logis" (artinya, "bagi pikiran manusia") hanyalah sebuah list dari things dengan beberapa lonceng dan peluit?

Apakah mewarisi dari List<T> selalu tidak bisa diterima? Kapan itu bisa diterima? Mengapa / mengapa tidak? Apa yang harus dipertimbangkan seorang programmer, ketika memutuskan apakah akan mewarisi dari List<T> atau tidak?


975
2018-02-11 03:01


asal


Jawaban:


Ada beberapa jawaban yang bagus di sini. Saya akan menambahkan kepada mereka poin-poin berikut.

Apa cara C # yang benar untuk merepresentasikan struktur data, yang "secara logis" (artinya, "bagi pikiran manusia") hanyalah daftar hal-hal dengan beberapa lonceng dan peluit?

Tanyakan kepada sepuluh orang non-komputer-programmer yang akrab dengan keberadaan sepakbola untuk mengisi kekosongan:

A football team is a particular kind of _____

Melakukan siapa saja katakan "daftar pemain sepak bola dengan beberapa lonceng dan peluit", atau apakah mereka semua mengatakan "tim olahraga" atau "klub" atau "organisasi"? Gagasan Anda bahwa tim sepak bola adalah jenis daftar pemain tertentu ada dalam pikiran manusia dan pikiran manusia Anda sendiri.

List<T> adalah mekanisme. Tim sepakbola adalah obyek bisnis - yaitu, sebuah objek yang mewakili beberapa konsep yang ada di dalam domain bisnis dari program. Jangan mencampurnya! Tim sepak bola adalah sejenis tim; saya t mempunyai sebuah daftar, daftar nama adalah daftar pemain. Daftar nama bukan a jenis daftar pemain tertentu. Daftar nama aku s daftar pemain. Jadi buatlah properti yang disebut Roster itu adalah List<Player>. Dan berhasil ReadOnlyList<Player> saat Anda melakukannya, kecuali Anda yakin bahwa semua orang yang tahu tentang tim sepak bola harus menghapus pemain dari daftar tersebut.

Apakah mewarisi dari List<T> selalu tidak bisa diterima?

Tidak bisa diterima siapa? Saya? Tidak.

Kapan itu bisa diterima?

Ketika Anda sedang membangun mekanisme itu meluas List<T> mekanisme.

Apa yang harus dipertimbangkan seorang programmer, ketika memutuskan apakah akan mewarisi dari List<T> atau tidak?

Apakah saya membangun sebuah mekanisme atau a obyek bisnis?

Tapi itu banyak kode! Apa yang saya dapatkan untuk semua pekerjaan itu?

Anda menghabiskan lebih banyak waktu mengetik pertanyaan Anda yang akan membuat Anda menulis metode penyampaian untuk anggota yang relevan List<T> lima puluh kali lipat. Anda jelas tidak takut dengan kata-kata kasar, dan kita berbicara tentang jumlah kode yang sangat kecil di sini; ini adalah beberapa menit kerja.

MEMPERBARUI

Saya memberikannya lebih banyak pemikiran dan ada alasan lain untuk tidak memodelkan tim sepak bola sebagai daftar pemain. Bahkan mungkin merupakan ide yang buruk untuk memodelkan tim sepak bola memiliki daftar pemain juga. Masalah dengan tim yang memiliki daftar pemain adalah bahwa apa yang Anda miliki adalah a foto dari tim tepat pada waktunya. Saya tidak tahu apa kasus bisnis Anda untuk kelas ini, tetapi jika saya memiliki kelas yang mewakili tim sepakbola, saya ingin mengajukan pertanyaan seperti "berapa banyak pemain Seahawks yang absen karena cedera antara 2003 dan 2013?" atau "Pemain Denver apa yang sebelumnya bermain untuk tim lain memiliki peningkatan tahun-ke-tahun terbesar dalam yard berlari?" atau "Apakah Piggers berjalan sepanjang jalan tahun ini?"

Artinya, tim sepak bola kelihatannya memiliki model yang baik kumpulan fakta-fakta sejarah seperti ketika seorang pemain direkrut, terluka, pensiun, dll. Jelas daftar pemain saat ini adalah fakta penting yang mungkin harus di depan dan pusat, tetapi mungkin ada hal menarik lainnya yang ingin Anda lakukan dengan objek ini yang memerlukan lebih banyak perspektif historis.


1137
2018-02-11 05:43



Terakhir, beberapa menyarankan membungkus Daftar dalam sesuatu:

Itu cara yang benar. "Tidak perlu bertele-tele" adalah cara yang buruk untuk melihat ini. Ini memiliki arti eksplisit ketika Anda menulis my_team.Players.Count. Anda ingin menghitung pemain.

my_team.Count

.. tidak berarti apa-apa. Hitung apa?

Sebuah tim bukanlah daftar - yang terdiri dari lebih dari sekadar daftar pemain. Sebuah tim memiliki pemain, jadi pemain harus menjadi bagian dari itu (anggota).

Jika kamu sangat khawatir tentang itu menjadi terlalu verbose, Anda selalu dapat mengekspos properti dari tim:

public int PlayerCount {
    get {
        return Players.Count;
    }
}

..yang menjadi:

my_team.PlayerCount

Ini memiliki arti sekarang dan patuh Hukum Demeter.

Anda juga harus mempertimbangkan untuk mengikuti Prinsip penggunaan kembali komposit. Dengan mewarisi dari List<T>, Anda mengatakan sebuah tim adalah daftar pemain dan mengekspos metode yang tidak perlu dari itu. Ini tidak benar - seperti yang Anda nyatakan, tim lebih dari daftar pemain: ia memiliki nama, manajer, anggota dewan, pelatih, staf medis, topi gaji, dll. Dengan memiliki kelas tim Anda berisi daftar pemain, Anda mengatakan "Tim mempunyai sebuah daftar pemain ", tetapi juga dapat memiliki hal-hal lain.


232
2018-02-11 03:05



Wow, posting Anda memiliki banyak pertanyaan dan poin. Sebagian besar alasan Anda dapatkan dari Microsoft adalah tepat. Mari kita mulai dengan segalanya List<T>

  • List<T>  aku s sangat dioptimalkan. Ini adalah penggunaan utama yang digunakan sebagai anggota pribadi suatu objek.
  • Microsoft tidak menyegelnya karena terkadang Anda mungkin ingin membuat kelas yang memiliki nama ramah: class MyList<T, TX> : List<CustomObject<T, Something<TX>> { ... }. Sekarang semudah melakukan var list = new MyList<int, string>();.
  • CA1002: Jangan mengekspos daftar generik: Pada dasarnya, bahkan jika Anda berencana untuk menggunakan aplikasi ini sebagai pengembang tunggal, ada baiknya untuk mengembangkan dengan praktik pengkodean yang baik, sehingga mereka menjadi ditanamkan ke Anda dan sifat kedua. Anda masih diizinkan untuk memaparkan daftar sebagai IList<T> jika Anda membutuhkan konsumen untuk memiliki daftar yang diindeks. Ini memungkinkan Anda mengubah implementasi dalam suatu kelas nanti.
  • Microsoft dibuat Collection<T> sangat generik karena itu adalah konsep generik ... nama mengatakan itu semua; itu hanya sebuah koleksi. Ada versi yang lebih tepat seperti SortedCollection<T>, ObservableCollection<T>, ReadOnlyCollection<T>, dll. masing-masing yang menerapkan IList<T> tapi tidak  List<T>.
  • Collection<T> memungkinkan untuk anggota (mis. Tambah, Hapus, dll.) untuk diganti karena mereka virtual. List<T> tidak.
  • Bagian terakhir dari pertanyaan Anda sangat tepat. Tim Sepakbola lebih dari sekadar daftar pemain, jadi itu harus menjadi kelas yang berisi daftar pemain itu. Berpikir Komposisi vs Warisan. Tim Sepakbola punya daftar pemain (daftar nama), itu bukan daftar pemain.

Jika saya menulis kode ini, kelas mungkin akan terlihat seperti ini:

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    // Yes. I used LINQ here. This is so I don't have to worry about
    // _roster.Length vs _roster.Count vs anything else.
    public int PlayerCount
    {
        get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

110
2018-02-11 03:26



class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal;
}

Kode sebelumnya berarti: sekelompok orang dari jalanan bermain sepak bola, dan mereka kebetulan memiliki nama. Sesuatu seperti:

People playing football

Pokoknya, kode ini (dari jawaban m-y)

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    public int PlayerCount
    {
    get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

Berarti: ini adalah tim sepak bola yang memiliki manajemen, pemain, admin, dll. Sesuatu seperti:

Image showing members (and other attributes) of the Manchester United team

Ini adalah bagaimana logika Anda disajikan dalam gambar ...


104
2018-02-11 15:45



Ini adalah contoh klasik dari komposisi vs warisan.

Dalam kasus khusus ini:

Apakah tim daftar pemain dengan perilaku tambahan

atau

Apakah tim merupakan objek tersendiri yang kebetulan berisi daftar pemain.

Dengan memperluas Daftar Anda membatasi diri Anda dalam beberapa cara:

  1. Anda tidak dapat membatasi akses (misalnya, menghentikan orang yang mengubah daftar). Anda mendapatkan semua metode Daftar apakah Anda perlu / menginginkannya semua atau tidak.

  2. Apa yang terjadi jika Anda ingin memiliki daftar hal-hal lain juga. Misalnya, tim memiliki pelatih, manajer, penggemar, peralatan, dll. Beberapa dari mereka mungkin menjadi daftar dalam hak mereka sendiri.

  3. Anda membatasi pilihan Anda untuk warisan. Misalnya Anda mungkin ingin membuat objek Tim generik, dan kemudian memiliki BaseballTeam, FootballTeam, dll. Yang mewarisi dari itu. Untuk mewarisi dari Daftar Anda perlu melakukan warisan dari Tim, tetapi itu berarti bahwa semua jenis tim yang berbeda dipaksa untuk memiliki penerapan yang sama dari daftar tersebut.

Komposisi - termasuk sebuah objek yang memberikan perilaku yang Anda inginkan di dalam objek Anda.

Inheritance - objek Anda menjadi sebuah instance dari objek yang memiliki perilaku yang Anda inginkan.

Keduanya memiliki kegunaannya, tetapi ini adalah kasus yang jelas di mana komposisi lebih disukai.


81
2018-02-11 10:58



Seperti yang telah ditunjukkan oleh semua orang, tim pemain bukanlah daftar pemain. Kesalahan ini dibuat oleh banyak orang di mana-mana, mungkin di berbagai tingkat keahlian. Seringkali masalahnya halus dan kadang-kadang sangat kotor, seperti dalam kasus ini. Desain semacam itu buruk karena ini melanggar Prinsip Pergantian Liskov. Internet memiliki banyak artikel bagus yang menjelaskan konsep ini misalnya, http://en.wikipedia.org/wiki/Liskov_substitution_principle 


43
2018-02-11 16:56



Bagaimana jika FootballTeam memiliki tim cadangan bersama dengan tim utama?

class FootballTeam
{
    List<FootballPlayer> Players { get; set; }
    List<FootballPlayer> ReservePlayers { get; set; }
}

Bagaimana Anda akan memodelkannya?

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

Hubungannya jelas mempunyai sebuah dan tidak adalah.

atau RetiredPlayers?

class FootballTeam
{
    List<FootballPlayer> Players { get; set; }
    List<FootballPlayer> ReservePlayers { get; set; }
    List<FootballPlayer> RetiredPlayers { get; set; }
}

Sebagai aturan praktis, jika Anda ingin mewarisi dari koleksi, beri nama kelas SomethingCollection.

Apakah Anda SomethingCollection semantis masuk akal? Lakukan ini hanya jika tipemu adalah koleksi Something.

Dalam kasus FootballTeam itu tidak terdengar benar. SEBUAH Team lebih dari a Collection. SEBUAH Team dapat memiliki pelatih, pelatih, dll seperti yang telah ditunjukkan oleh jawaban lainnya.

FootballCollection Kedengarannya seperti koleksi bola atau mungkin koleksi perlengkapan sepakbola. TeamCollection, kumpulan tim.

FootballPlayerCollection Kedengarannya seperti koleksi pemain yang akan menjadi nama yang valid untuk kelas yang mewarisi dari List<FootballPlayer> jika kamu benar-benar ingin melakukan itu.

Sangat List<FootballPlayer> adalah tipe yang sangat bagus untuk ditangani. Mungkin IList<FootballPlayer> jika Anda mengembalikannya dari suatu metode.

kesimpulan

Bertanya pada diri sendiri

  1. Aku s  X Sebuah Y? atau Has  X Sebuah Y?

  2. Apakah nama kelas saya berarti apa itu?


34
2018-02-12 11:41



Pertama-tama, itu ada hubungannya dengan kegunaan. Jika Anda menggunakan warisan, itu Team kelas akan mengekspos perilaku (metode) yang dirancang murni untuk manipulasi objek. Sebagai contoh, AsReadOnly() atau CopyTo(obj) metode tidak masuk akal untuk objek tim. Alih-alih AddRange(items) metode yang Anda mungkin ingin lebih deskriptif AddPlayers(players) metode.

Jika Anda ingin menggunakan LINQ, terapkan antarmuka umum seperti ICollection<T> atau IEnumerable<T> akan lebih masuk akal.

Seperti disebutkan, komposisi adalah cara yang tepat untuk melakukannya. Cukup terapkan daftar pemain sebagai variabel pribadi.


27
2018-02-11 03:25



Desain> Implementasi

Metode dan properti apa yang Anda paparkan adalah keputusan desain. Apa kelas dasar Anda mewarisi dari adalah detail implementasi. Saya merasa perlu melangkah mundur ke yang pertama.

Objek adalah kumpulan data dan perilaku.

Jadi pertanyaan pertama Anda seharusnya:

  • Data apa yang objek ini termasuk dalam model yang saya buat?
  • Perilaku apa yang ditampilkan objek ini dalam model itu?
  • Bagaimana ini bisa berubah di masa depan?

Ingatlah bahwa pewarisan mengimplikasikan hubungan "isa" (is a), sedangkan komposisi menyiratkan hubungan "has a" (hasa). Pilih yang tepat untuk situasi Anda dalam pandangan Anda, ingatlah di mana hal-hal mungkin terjadi saat aplikasi Anda berevolusi.

Pertimbangkan berpikir dalam antarmuka sebelum Anda berpikir dalam tipe konkret, karena beberapa orang merasa lebih mudah untuk menempatkan otak mereka dalam "mode desain" seperti itu.

Ini bukanlah sesuatu yang setiap orang lakukan secara sadar pada tingkat ini dalam pengkodean sehari-hari. Tetapi jika Anda mempertimbangkan topik semacam ini, Anda melangkah di perairan desain. Menyadari hal itu bisa membebaskan.

Pertimbangkan Spesifikasi Desain

Lihatlah Daftar <T> dan IList <T> di MSDN atau Visual Studio. Lihat metode dan properti apa yang mereka paparkan. Apakah semua metode ini terlihat seperti sesuatu yang ingin dilakukan seseorang kepada FootballTeam dalam pandangan Anda?

Apakah footballTeam.Reverse () masuk akal bagi Anda? Apakah footballTeam.ConvertAll <TOutput> () terlihat seperti sesuatu yang Anda inginkan?

Ini bukan pertanyaan jebakan; jawabannya mungkin benar-benar "ya". Jika Anda menerapkan / mewarisi Daftar <Player> atau IList <Player>, Anda terjebak dengan mereka; jika itu ideal untuk model Anda, lakukanlah.

Jika Anda memutuskan ya, itu masuk akal, dan Anda ingin objek Anda dapat diperlakukan sebagai koleksi / daftar pemain (perilaku), dan karena itu Anda ingin menerapkan ICollection atau IList, dengan segala cara melakukannya. Secara Notional:

class FootballTeam : ... ICollection<Player>
{
    ...
}

Jika Anda ingin objek Anda berisi koleksi / daftar pemain (data), dan oleh karena itu Anda ingin koleksi atau daftar menjadi properti atau anggota, dengan segala cara melakukannya. Secara Notional:

class FootballTeam ...
{
    public ICollection<Player> Players { get { ... } }
}

Anda mungkin merasa bahwa Anda ingin orang-orang hanya dapat menyebutkan satu set pemain, daripada menghitungnya, menambah mereka atau menghapusnya. IEnumerable <Player> adalah opsi yang sangat valid untuk dipertimbangkan.

Anda mungkin merasa bahwa tidak satu pun dari antarmuka ini berguna dalam model Anda sama sekali. Ini kurang mungkin (IEnumerable <T> berguna dalam banyak situasi) tetapi masih mungkin.

Siapa pun yang mencoba memberi tahu Anda bahwa salah satunya adalah secara pasti dan definitif salah dalam setiap kasus salah arah. Siapa pun yang mencoba memberi tahu Anda itu pasti dan pasti kanan dalam setiap kasus salah arah.

Pindah ke Implementasi

Setelah Anda memutuskan data dan perilaku, Anda dapat membuat keputusan tentang implementasi. Ini termasuk kelas-kelas konkret apa yang Anda andalkan pada melalui warisan atau komposisi.

Ini mungkin bukan langkah besar, dan orang sering mengaitkan desain dan implementasi karena sangat mungkin untuk menjalankan semuanya di kepala Anda dalam satu atau dua detik dan mulai mengetik.

Percobaan Pemikiran

Contoh tiruan: seperti yang telah disebutkan orang lain, sebuah tim tidak selalu "hanya" sebagai koleksi pemain. Apakah Anda mempertahankan koleksi skor pertandingan untuk tim? Apakah tim dipertukarkan dengan klub, dalam model Anda? Jika demikian, dan jika tim Anda adalah koleksi pemain, mungkin itu juga merupakan kumpulan staf dan / atau kumpulan skor. Maka Anda berakhir dengan:

class FootballTeam : ... ICollection<Player>, 
                         ICollection<StaffMember>,
                         ICollection<Score>
{
    ....
}

Meskipun tidak ada desain, pada titik ini di C # Anda tidak akan dapat mengimplementasikan semua ini dengan mewarisi dari List <T>, karena C # "only" mendukung warisan tunggal. (Jika Anda sudah mencoba malarky ini di C ++, Anda dapat menganggap ini sebagai Hal yang Baik.) Menerapkan satu koleksi melalui warisan dan satu melalui komposisi cenderung merasa kotor. Dan properti seperti Count menjadi membingungkan bagi pengguna kecuali Anda menerapkan ILIst <Player> .Count dan IList <StaffMember> .Jumlah, dll. Secara eksplisit, dan kemudian mereka hanya menyakitkan daripada membingungkan. Anda dapat melihat ke mana hal ini terjadi; firasat saat memikirkan jalan ini mungkin memberi tahu Anda rasanya salah untuk menuju ke arah ini (dan benar atau salah, rekan Anda mungkin juga jika Anda menerapkannya dengan cara ini!)

Jawaban Singkat (Terlambat)

Panduan tentang tidak mewarisi dari kelas koleksi tidak khusus C #, Anda akan menemukannya di banyak bahasa pemrograman. Sudah diterima kebijaksanaan bukan hukum. Salah satu alasannya adalah bahwa dalam praktek komposisi dianggap sering menang atas warisan dalam hal komprehensibilitas, implementabilitas dan pemeliharaan. Ini lebih umum dengan objek dunia nyata / domain untuk menemukan hubungan "hasa" yang berguna dan konsisten daripada hubungan "isa" yang berguna dan konsisten kecuali jika Anda jauh di dalam abstrak, terutama seiring berjalannya waktu dan data dan perilaku objek yang tepat dalam kode perubahan. Ini seharusnya tidak menyebabkan Anda selalu mengesampingkan mewarisi dari kelas koleksi; tetapi mungkin sugestif.


25
2018-02-11 22:27