Saya sedang membaca artikel pemrograman dan disebutkan pola dekorator. Saya telah memprogram untuk sementara waktu tetapi tanpa pendidikan atau pelatihan formal apa pun, tetapi saya mencoba mempelajari tentang pola standar dan semacamnya.
Jadi saya mencari Dekorator, dan menemukan artikel Wikipedia di atasnya. Saya sekarang mengerti konsep pola Penghias, tetapi saya agak bingung dengan bagian ini:
Sebagai contoh, pertimbangkan sebuah jendela dalam sistem windowing. Untuk mengizinkan pengguliran konten jendela, kami mungkin ingin menambahkan scrollbar horizontal atau vertikal, sesuai keperluan. Asumsikan windows diwakili oleh instance dari kelas Window, dan menganggap kelas ini tidak memiliki fungsionalitas untuk menambahkan scrollbar. Kita bisa membuat ScrollingWindow subclass yang menyediakannya, atau kita bisa membuat ScrollingWindowDecorator yang menambahkan fungsionalitas ini ke objek Window yang ada. Pada titik ini, solusi mana pun akan baik-baik saja.
Sekarang mari kita asumsikan kita juga menginginkan kemampuan untuk menambahkan batas pada windows kita. Sekali lagi, kelas Window asli kami tidak memiliki dukungan. Subclass ScrollingWindow sekarang menimbulkan masalah, karena telah secara efektif menciptakan jendela jenis baru. Jika kita ingin menambahkan dukungan perbatasan ke semua jendela, kita harus membuat subkelas WindowWithBorder dan ScrollingWindowWithBorder. Jelas, masalah ini semakin buruk dengan setiap fitur baru yang akan ditambahkan. Untuk solusi dekorator, kita cukup membuat BorderedWindowDecorator baru — saat runtime, kita dapat mendekorasi jendela yang ada dengan ScrollingWindowDecorator atau BorderedWindowDecorator atau keduanya, sesuai keinginan kita.
OK, ketika mereka mengatakan untuk menambahkan perbatasan ke semua jendela, mengapa tidak menambahkan fungsionalitas ke dalam kelas Window asli untuk memungkinkan opsi? Seperti yang saya lihat, subkelas hanya untuk menambahkan fungsionalitas spesifik ke kelas, atau mengganti metode kelas. Jika saya perlu menambahkan fungsionalitas ke semua objek yang ada, mengapa saya tidak memodifikasi superclass saja?
Ada baris lain di artikel itu:
Pola dekorator adalah alternatif untuk subclassing. Subkelas menambahkan perilaku pada waktu kompilasi, dan perubahan memengaruhi semua instance kelas asli; mendekorasi dapat memberikan perilaku baru pada saat run-time untuk objek individu.
Saya tidak mendapatkan apa yang mereka katakan "... perubahan memengaruhi semua instance dari kelas asli" - bagaimana subklas mengubah kelas induk? Bukankah itu inti dari subklasifikasi?
Saya akan berasumsi bahwa artikel itu, seperti banyak Wiki, tidak ditulis dengan jelas. Saya bisa melihat kegunaan Penghias di baris terakhir - "... memberikan perilaku baru saat run-time untuk objek individu."
Tanpa membaca tentang pola ini, jika saya perlu mengubah perilaku pada saat run-time untuk masing-masing objek, saya mungkin akan membangun beberapa metode menjadi super atau subkelas untuk mengaktifkan / menonaktifkan perilaku tersebut. Tolong bantu saya benar-benar memahami kegunaan Dekorator, dan mengapa pemikiran pemula saya cacat?
Jawaban:
Pola dekorator adalah yang lebih menyukai komposisi daripada warisan [paradigma OOP lain yang berguna untuk dipelajari]
Manfaat utama dari pola dekorator - lebih dari subclassing adalah untuk memungkinkan lebih banyak opsi campuran & cocok. Jika Anda memiliki, misalnya, 10 perilaku berbeda yang dimiliki oleh sebuah jendela, maka ini berarti - dengan subkelas - Anda perlu membuat setiap kombinasi yang berbeda, yang juga pasti akan menyertakan banyak penggunaan kembali kode.
Namun, apa yang terjadi ketika Anda memutuskan untuk menambahkan perilaku baru?
Dengan dekorator, Anda hanya menambahkan kelas baru yang menjelaskan perilaku ini, dan hanya itu - polanya memungkinkan Anda untuk secara efektif memasukkan ini tanpa modifikasi pada sisa kode.
Dengan subklasifikasi, Anda mendapatkan mimpi buruk.
Satu pertanyaan yang Anda ajukan adalah "bagaimana subklas mengubah kelas induk?" Bukannya itu mengubah kelas induk; ketika ia mengatakan sebuah instance, itu berarti objek apa pun yang Anda 'instantiated' [jika Anda menggunakan Java atau C #, misalnya, dengan menggunakan
new
perintah]. Maksudnya adalah, ketika Anda menambahkan perubahan ini ke kelas, Anda tidak punya pilihan untuk perubahan itu ada di sana, bahkan jika Anda tidak benar-benar membutuhkannya.Atau, Anda dapat menempatkan semua fungsinya ke dalam satu kelas dengan itu dihidupkan / dimatikan melalui bendera ... tetapi ini berakhir dengan satu kelas yang menjadi lebih besar dan lebih besar seiring proyek Anda tumbuh.
Bukan hal yang aneh untuk memulai proyek Anda dengan cara ini, dan refactor menjadi pola dekorator setelah Anda mencapai massa kritis yang efektif.
Poin menarik yang harus dibuat: Anda dapat menambahkan fungsi yang sama beberapa kali; jadi Anda bisa, misalnya, memiliki jendela dengan jumlah ganda, tiga kali lipat atau berapa pun atau batas yang Anda butuhkan.
Poin utama dari pola ini adalah untuk mengaktifkan perubahan run-time: Anda mungkin tidak tahu bagaimana Anda ingin melihat jendela sampai program berjalan, dan ini memungkinkan Anda untuk memodifikasinya dengan mudah. Memang, ini bisa dilakukan melalui subclassing, tetapi tidak sebaik itu.
Dan akhirnya, memungkinkan fungsionalitas ditambahkan ke kelas yang mungkin tidak dapat Anda edit - misalnya di kelas yang disegel / final, atau yang disediakan dari API lain
sumber
Pertimbangkan kemungkinan menambahkan scrollbar dan batas dengan subclassing. Jika Anda menginginkan setiap kemungkinan, Anda mendapatkan empat kelas (Python):
Sekarang, dalam
WindowWithScrollBarAndBorder.draw()
, jendela ditarik dua kali, dan kedua kalinya mungkin atau mungkin tidak menimpa Scrollbar yang sudah ditarik, tergantung pada implementasinya. Jadi kode turunan Anda sangat terkait dengan implementasi kelas lain, dan Anda harus peduli tentang hal itu setiap kali Anda mengubahWindow
perilaku kelas. Sebuah solusi adalah dengan menyalin-menempelkan kode dari kelas super ke kelas turunan dan menyesuaikannya dengan kebutuhan kelas turunan, tetapi setiap perubahan dalam kelas super harus disalin-tempel lagi dan disesuaikan lagi, jadi sekali lagi kelas turunannya adalah tergabung erat dengan kelas dasar (melalui kebutuhan untuk copy-paste-menyesuaikan). Masalah lain adalah bahwa jika Anda membutuhkan properti lain yang mungkin atau mungkin tidak dimiliki jendela, Anda harus menggandakan setiap kelas:Itu berarti untuk satu set fitur yang saling independen f dengan | f | sebagai jumlah fitur, Anda harus mendefinisikan 2 ** | f | kelas, mis. jika Anda memiliki 10 fitur, Anda mendapatkan 1024 kelas yang sangat rapat. Jika Anda menggunakan Pola Penghias, setiap fitur dapatkan kelasnya yang independen dan longgar dan Anda hanya memiliki 1 + | f | kelas (itu 11 untuk contoh di atas).
sumber
Saya bukan ahli dalam pola khusus ini, tetapi seperti yang saya lihat, pola dekorator dapat diterapkan ke kelas yang Anda mungkin tidak memiliki kemampuan untuk mengubah atau sub-kelas (mereka mungkin bukan kode Anda dan disegel, misalnya ). Dalam contoh Anda, bagaimana jika Anda tidak menulis kelas Window tetapi hanya mengkonsumsinya? Selama kelas Window memiliki antarmuka dan Anda memprogram melawan antarmuka itu, Dekorator Anda dapat menggunakan antarmuka yang sama tetapi memperluas fungsionalitasnya.
Contoh yang Anda sebutkan sebenarnya dibahas di sini dengan cukup rapi:
http://www.oodesign.com/decorator-pattern.html
sumber