Pertanyaan Lebih suka komposisi daripada warisan?


Mengapa lebih memilih komposisi daripada warisan? Apa untung-untungan yang ada untuk setiap pendekatan? Kapan sebaiknya Anda memilih warisan atas komposisi?


1348
2017-09-08 01:58


asal


Jawaban:


Lebih suka komposisi lebih dari warisan karena lebih mudah dibentuk / mudah untuk dimodifikasi nanti, tetapi jangan menggunakan pendekatan compose-always. Dengan komposisi, mudah untuk mengubah perilaku dengan cepat dengan Ketergantungan Injeksi / Setter. Warisan lebih kaku karena sebagian besar bahasa tidak memungkinkan Anda untuk berasal dari lebih dari satu jenis. Jadi angsa lebih atau kurang matang setelah Anda berasal dari TypeA.

Uji asam saya untuk hal di atas adalah:

  • Apakah TypeB ingin mengekspos antarmuka lengkap (semua metode publik tidak kurang) dari TypeA sehingga TypeB dapat digunakan di mana TypeA diharapkan? Menunjukkan Warisan.

misalnya A Cessna biplane akan mengekspos antarmuka lengkap pesawat terbang, jika tidak lebih. Sehingga membuatnya cocok untuk berasal dari Airplane.

  • Apakah TypeB hanya menginginkan sebagian / bagian dari perilaku yang diekspos oleh TypeA? Menunjukkan kebutuhan untuk Komposisi. 

misalnya Seekor Burung mungkin hanya membutuhkan perilaku terbang dari Pesawat Terbang. Dalam hal ini, masuk akal untuk mengekstraknya sebagai antarmuka / kelas / keduanya dan menjadikannya anggota dari kedua kelas.

Memperbarui: Baru saja kembali ke jawaban saya dan sepertinya sekarang itu tidak lengkap tanpa penyebutan khusus dari Barbara Liskov Prinsip Pergantian Liskov sebagai ujian untuk 'Haruskah saya mewarisi dari jenis ini?'


1010
2017-09-10 03:04



Pikirkan containment sebagai a mempunyai sebuah hubungan. Mobil "memiliki" mesin, seseorang "memiliki" nama, dll.

Pikirkan pewarisan sebagai adalah hubungan. Mobil "adalah" kendaraan, seseorang "adalah" mamalia, dll.

Saya tidak menerima penghargaan untuk pendekatan ini. Saya mengambilnya langsung dari Edisi Kedua Kode Lengkap oleh Steve McConnell, Bagian 6.3.


347
2017-09-08 02:09



Jika Anda memahami perbedaannya, lebih mudah untuk dijelaskan.

Kode prosedural

Contoh dari ini adalah PHP tanpa menggunakan kelas (terutama sebelum PHP5). Semua logika dikodekan dalam satu set fungsi. Anda dapat menyertakan file lain yang berisi fungsi pembantu dan seterusnya serta melakukan logika bisnis Anda dengan meneruskan data ke dalam fungsi. Ini bisa sangat sulit untuk dikelola saat aplikasi tumbuh. PHP5 mencoba untuk memperbaikinya dengan menawarkan desain yang lebih berorientasi objek.

Warisan

Ini mendorong penggunaan kelas. Inheritance adalah salah satu dari tiga prinsip desain OO (pewarisan, polimorfisme, enkapsulasi).

class Person {
   String Title;
   String Name;
   Int Age
}

class Employee : Person {
   Int Salary;
   String Title;
}

Ini adalah warisan di tempat kerja. Karyawan "adalah" Orang atau mewarisi dari Orang. Semua hubungan warisan adalah hubungan "is-a". Karyawan juga bayangan properti Judul dari Orang, yang berarti Employee.Title akan mengembalikan Judul untuk Karyawan bukan Orang.

Komposisi

Komposisi lebih disukai daripada pewarisan. Sederhananya, Anda akan memiliki:

class Person {
   String Title;
   String Name;
   Int Age;

   public Person(String title, String name, String age) {
      this.Title = title;
      this.Name = name;
      this.Age = age;
   }

}

class Employee {
   Int Salary;
   private Person person;

   public Employee(Person p, Int salary) {
       this.person = p;
       this.Salary = salary;
   }
}

Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);

Komposisi biasanya "memiliki" atau "menggunakan" hubungan. Di sini kelas Karyawan memiliki Orang. Itu tidak mewarisi dari Person tetapi malah membuat objek Person dilewatkan ke itu, itulah mengapa ia "memiliki" Person.

Komposisi atas Warisan

Sekarang katakan Anda ingin membuat tipe Manajer sehingga Anda akan mendapatkan:

class Manager : Person, Employee {
   ...
}

Contoh ini akan berfungsi dengan baik, bagaimana jika Orang dan Karyawan menyatakannya Title? Haruskah Manajer.Title mengembalikan "Manajer Operasi" atau "Tuan"? Dalam komposisi, ambiguitas ini ditangani lebih baik:

Class Manager {
   public Title;
   public Manager(Person p, Employee e)
   {
      this.Title = e.Title;
   }
}

Objek Manajer disusun sebagai Karyawan dan Orang. Perilaku Judul diambil dari karyawan. Komposisi eksplisit ini menghilangkan ambiguitas di antara hal-hal lain dan Anda akan menemukan lebih sedikit bug.


175
2018-05-21 07:54



Dengan semua manfaat tak terbantahkan yang diberikan oleh warisan, inilah beberapa kerugiannya.

Kekurangan Warisan:

  1. Anda tidak dapat mengubah implementasi yang diwarisi dari kelas super saat runtime (jelas karena pewarisan ditentukan pada waktu kompilasi).
  2. Warisan mengekspos subkelas ke rincian implementasi kelas induknya, itulah mengapa sering dikatakan bahwa warisan melanggar enkapsulasi (dalam arti bahwa Anda benar-benar perlu fokus pada antarmuka hanya tidak implementasi, jadi penggunaan kembali oleh sub classing tidak selalu disukai).
  3. Kopling ketat yang disediakan oleh warisan membuat implementasi subclass sangat terikat dengan implementasi kelas super bahwa setiap perubahan dalam implementasi induk akan memaksa kelas sub untuk berubah.
  4. Penggunaan ulang yang berlebihan dengan sub-classing dapat membuat tumpukan warisan sangat dalam dan sangat membingungkan juga.

Di samping itu Komposisi objek didefinisikan saat runtime melalui objek yang memperoleh referensi ke objek lain. Dalam kasus seperti benda-benda ini tidak akan pernah dapat mencapai data yang dilindungi masing-masing (tidak ada istirahat enkapsulasi) dan akan dipaksa untuk menghormati antarmuka masing-masing. Dan dalam hal ini juga, dependensi implementasi akan jauh lebih sedikit daripada dalam hal warisan.


91
2018-05-21 08:34



Alasan lain yang sangat pragmatis, untuk lebih memilih komposisi daripada warisan ada hubungannya dengan model domain Anda, dan memetakannya ke database relasional. Sangat sulit untuk memetakan warisan ke model SQL (Anda berakhir dengan segala macam workarounds peretasan, seperti membuat kolom yang tidak selalu digunakan, menggunakan tampilan, dll). Beberapa ORML mencoba untuk menangani ini, tetapi itu selalu menjadi rumit dengan cepat. Komposisi dapat dengan mudah dimodelkan melalui hubungan foreign-key antara dua tabel, tetapi pewarisan jauh lebih sulit.


77
2017-09-08 02:48



Sementara dengan kata-kata singkat saya setuju dengan "Lebih suka komposisi daripada warisan", sangat sering bagi saya kedengarannya seperti "lebih suka kentang daripada coca-cola". Ada tempat untuk pewarisan dan tempat untuk komposisi. Anda perlu memahami perbedaan, maka pertanyaan ini akan hilang. Apa yang benar-benar berarti bagi saya adalah "jika Anda akan menggunakan warisan - pikirkan lagi, kemungkinan Anda membutuhkan komposisi".

Anda harus lebih memilih kentang daripada coca cola ketika Anda ingin makan, dan coca cola di atas kentang ketika Anda ingin minum.

Membuat subkelas seharusnya berarti lebih dari sekadar cara mudah untuk memanggil metode superclass. Anda harus menggunakan warisan ketika subclass "adalah-a" kelas super baik secara struktural dan fungsional, ketika dapat digunakan sebagai superclass dan Anda akan menggunakannya. Jika bukan itu masalahnya - itu bukan warisan, tetapi sesuatu yang lain. Komposisi adalah ketika objek Anda terdiri dari yang lain, atau memiliki beberapa hubungan dengan mereka.

Jadi bagi saya sepertinya jika seseorang tidak tahu apakah dia membutuhkan warisan atau komposisi, masalah sebenarnya adalah dia tidak tahu apakah dia ingin minum atau makan. Pikirkan tentang masalah domain Anda lebih banyak, pahami dengan lebih baik.


64
2018-05-08 22:29



Warisan cukup menarik terutama berasal dari prosedural-tanah dan sering terlihat elegan. Maksud saya, yang perlu saya lakukan adalah menambahkan sedikit fungsi ini ke beberapa kelas lain, bukan? Nah, salah satu masalahnya adalah itu

Warisan mungkin adalah bentuk kopling terburuk yang bisa Anda miliki

Kelas dasar Anda memecah enkapsulasi dengan mengekspos rincian implementasi ke subclass dalam bentuk anggota yang dilindungi. Ini membuat sistem Anda kaku dan rapuh. Namun, cacat yang lebih tragis adalah subkelas baru yang membawa semua bagasi dan pendapat dari rantai warisan.

Artikel, Warisan adalah Kejahatan: Epic Gagal dari DataAnnotationsModelBinder, berjalan melalui contoh ini di C #. Ini menunjukkan penggunaan warisan ketika komposisi seharusnya digunakan dan bagaimana itu bisa direproduksi.


54
2018-01-23 19:55



Di Java atau C #, suatu objek tidak dapat mengubah tipenya begitu telah dipakai.

Jadi, jika objek Anda harus muncul sebagai objek yang berbeda atau berperilaku berbeda tergantung pada keadaan atau kondisi objek, kemudian gunakan Komposisi: Mengacu pada Negara dan Strategi Pola desain.

Jika objek harus bertipe sama, maka gunakan Warisan atau mengimplementasikan antarmuka.


37
2017-09-08 02:25