Kapan menggunakan ciri-ciri, yang bertentangan dengan warisan dan komposisi?

9

Ada tiga cara umum, AFAIK, untuk menerapkan reusability ketika datang ke OOP

  1. Warisan: biasanya mewakili is-a relationship (bebek is-a bird)
  2. Komposisi: biasanya mewakili has-a relationship (mobil memiliki-mesin)
  3. Ciri (mis. Kata kunci ciri dalam PHP): ... tidak terlalu yakin tentang ini

Sementara bagi saya kelihatannya sifat-sifat dapat mengimplementasikan hubungan has-a dan is-a, saya tidak begitu yakin model seperti apa yang dimaksudkan untuk itu. Situasi seperti apa yang dirancang untuk sifat-sifat itu?

Extrakun
sumber
Anda mungkin menjelaskan sedikit lebih banyak tentang ciri-ciri, tetapi bisakah ciri-ciri hanya menjadi kata lain untuk komposisi?
Trilarion
1
Saya benar-benar ingin tahu mengapa juga. Belum pernah menggunakannya.
Andy

Jawaban:

6

Ciri adalah cara lain untuk melakukan komposisi. Pikirkan mereka sebagai cara untuk menyusun semua bagian kelas pada waktu kompilasi (atau waktu kompilasi JIT), merakit implementasi konkret dari bagian-bagian yang akan Anda butuhkan.

Pada dasarnya, Anda ingin menggunakan ciri-ciri ketika Anda menemukan diri Anda membuat kelas dengan kombinasi fitur yang berbeda. Situasi ini muncul paling sering untuk orang-orang menulis perpustakaan fleksibel untuk dikonsumsi orang lain. Misalnya, inilah deklarasi kelas unit test yang saya tulis baru-baru ini menggunakan ScalaTest :

class TestMyClass
  extends WordSpecLike
  with Matchers
  with MyCustomTrait
  with BeforeAndAfterAll
  with BeforeAndAfterEach
  with ScalaFutures

Kerangka uji unit memiliki banyak opsi konfigurasi yang berbeda, dan setiap tim memiliki preferensi yang berbeda tentang bagaimana mereka ingin melakukan sesuatu. Dengan menempatkan opsi-opsi ke dalam sifat-sifat (yang dicampur digunakan withdalam Scala), ScalaTest dapat menawarkan semua opsi tersebut tanpa harus membuat nama kelas seperti WordSpecLikeWithMatchersAndFutures, atau satu ton runtime boolean flag seperti WordSpecLike(enableFutures, enableMatchers, ...). Ini membuatnya mudah untuk mengikuti prinsip Terbuka / tertutup . Anda dapat menambahkan fitur baru, dan kombinasi fitur baru, cukup dengan menambahkan sifat baru. Ini juga membuatnya lebih mudah untuk mengikuti Prinsip Segregasi Antarmuka , karena Anda dapat dengan mudah memasukkan fungsi yang tidak diperlukan secara universal ke dalam suatu sifat.

Ciri juga merupakan cara yang baik untuk meletakkan kode umum ke beberapa kelas yang tidak masuk akal untuk berbagi hierarki warisan. Warisan adalah hubungan yang sangat erat, dan Anda tidak harus membayar biaya itu jika Anda dapat membantunya. Ciri-ciri adalah hubungan yang jauh lebih longgar. Dalam contoh saya di atas, saya biasa MyCustomTraitdengan mudah berbagi implementasi database tiruan antara beberapa kelas tes yang tidak terkait.

Ketergantungan injeksi mencapai banyak tujuan yang sama, tetapi pada saat runtime berdasarkan input pengguna dan bukan pada waktu kompilasi berdasarkan input programmer. Ciri juga lebih ditujukan untuk dependensi yang secara semantik bagian dari kelas yang sama. Anda semacam merakit bagian-bagian dari satu kelas daripada menelepon ke kelas lain dengan tanggung jawab lain.

Kerangka kerja injeksi ketergantungan mencapai banyak tujuan yang sama pada waktu kompilasi berdasarkan input programmer, tetapi sebagian besar merupakan solusi untuk bahasa pemrograman tanpa dukungan sifat yang tepat. Ciri membawa dependensi ini ke dalam bidang pemeriksa tipe kompiler, dengan sintaks yang lebih bersih, dengan proses pembuatan yang lebih sederhana, yang membuat perbedaan yang lebih jelas antara dependensi waktu kompilasi dan runtime.

Karl Bielefeldt
sumber
Hai, ini jawaban yang bagus. Bolehkah saya bertanya bagaimana memutuskan kapan harus menggunakan ciri-ciri, dan kapan harus menggunakan injeksi ketergantungan. yang tampaknya akan mencapai hal yang sama.
Extrakun
Pengamatan cerdas. Lihat hasil edit saya.
Karl Bielefeldt
Terima kasih telah menulis ini. Saya ingin tahu tentang jawaban Anda tentang sifat-sifat seperti komposisi @KarlBielefeldt. Kelas Anda dapat digunakan di mana saja sifat itu diperlukan, dan Anda masih akan menderita kerapuhan yang sama dengan antarmuka biasa. Jadi sepertinya lebih dekat dengan subtipe dan warisan, bukan? Saya juga tidak yakin bagaimana ini mirip dengan DI ... jika Anda memiliki berbagai kelas yang didefinisikan yang memperluas sifat, maka bukankah dependensi konkret tersebut didefinisikan di mana pun dalam hierarki yang didefinisikan oleh kelas, alih-alih pada titik entri / atas dari kode? Terima kasih!
allstar
Ciri dapat digunakan seperti antarmuka, untuk properti pewarisannya, tetapi bukan itu yang membuatnya unik. The withoperator adalah apa yang membedakan mereka, dan withadalah operasi komposisi. Dan ya, sifat-sifat menggantikan DI tanpa harus didefinisikan pada titik masuk kode. Itulah salah satu hal yang membuat mereka lebih disukai menurut saya.
Karl Bielefeldt