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 with
dalam 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 MyCustomTrait
dengan 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.