Dalam beberapa tahun terakhir, bahasa yang saya suka gunakan menjadi semakin "fungsional". Saya sekarang menggunakan bahasa yang merupakan semacam "hibrid": C #, F #, Scala. Saya suka merancang aplikasi saya menggunakan kelas yang sesuai dengan objek domain, dan menggunakan fitur fungsional di mana ini membuat pengkodean lebih mudah, lebih bertepatan dan lebih aman (terutama ketika beroperasi pada koleksi atau ketika melewati fungsi).
Namun kedua dunia "bentrok" ketika datang ke pola desain. Contoh spesifik yang saya hadapi baru-baru ini adalah pola Observer. Saya ingin produser memberi tahu beberapa kode lain ("konsumen / pengamat", katakanlah penyimpanan DB, logger, dan sebagainya) ketika suatu item dibuat atau diubah.
Saya awalnya melakukannya "secara fungsional" seperti ini:
producer.foo(item => { updateItemInDb(item); insertLog(item) })
// calls the function passed as argument as an item is processed
Tapi sekarang saya bertanya-tanya apakah saya harus menggunakan pendekatan yang lebih "OO":
interface IItemObserver {
onNotify(Item)
}
class DBObserver : IItemObserver ...
class LogObserver: IItemObserver ...
producer.addObserver(new DBObserver)
producer.addObserver(new LogObserver)
producer.foo() //calls observer in a loop
Apa pro dan kontra dari kedua pendekatan tersebut? Saya pernah mendengar seorang guru FP mengatakan bahwa pola desain ada hanya karena keterbatasan bahasa, dan itulah sebabnya ada begitu sedikit dalam bahasa fungsional. Mungkin ini bisa menjadi contohnya?
EDIT: Dalam skenario khusus saya, saya tidak membutuhkannya, tapi .. bagaimana Anda menerapkan penghapusan dan penambahan "pengamat" dengan cara fungsional? (Yaitu bagaimana Anda menerapkan semua fungsionalitas dalam pola?) Baru saja melewati fungsi baru, misalnya?
sumber
Jawaban:
Itu adalah contoh yang baik dari dua pendekatan berbeda yang mengusung gagasan melakukan tugas di luar batas kepedulian terhadap objek pemanggil.
Meskipun jelas dalam contoh ini bahwa Anda harus menggunakan pendekatan fungsional, secara umum itu akan benar-benar tergantung pada seberapa kompleks perilaku objek yang dipanggil harus ditunjukkan. Jika itu benar-benar masalah perilaku yang kompleks, di mana Anda akan menemukan diri Anda sering menerapkan logika yang sama, dan generator fungsi tidak dapat digunakan untuk mengekspresikannya dengan jelas, maka Anda mungkin ingin menggunakan komposisi kelas atau pewarisan, di mana Anda akan memiliki sedikit lebih banyak kebebasan untuk menggunakan kembali dan memperluas perilaku yang ada secara ad-hoc.
Namun, satu pola yang saya amati adalah bahwa biasanya para pengembang memilih pendekatan fungsional pada awalnya dan hanya sekali permintaan akan perilaku yang lebih terperinci muncul, mereka memutuskan untuk menggunakan pendekatan berbasis kelas. Saya tahu, misalnya, Django beralih dari tampilan berbasis fungsi, template loader, dan pelari uji ke yang berbasis kelas begitu manfaat dan persyaratan menjadi jelas, tetapi tidak sebelum itu.
sumber
Versi fungsionalnya jauh lebih pendek, lebih mudah dirawat, lebih mudah dibaca, dan secara umum, sangat unggul dalam hampir semua hal yang bisa dibayangkan.
Meskipun banyak, jauh dari semua pola adalah untuk menebus kurangnya fitur dalam OOP, seperti Pengamat. Itu jauh lebih baik dimodelkan secara fungsional.
sumber
"Guru FP" Anda sebagian benar; banyak pola OO yang diretas untuk melakukan hal-hal fungsional. (Klaimnya bahwa inilah alasan mengapa hanya sedikit bahasa FP yang kelihatannya meragukan). Pola Pengamat dan Strategi mencoba meniru fungsi-fungsi kelas satu. Pola Pengunjung adalah retasan untuk mensimulasikan pencocokan pola. Anda
IItemObserver
hanya sebuah fungsi yang menyamar. Berpura-pura itu berbeda dari fungsi lain yang mengambil item tidak membelikanmu apa pun.Objek hanyalah satu jenis abstraksi data. Makalah ini akan membantu menjelaskan topik itu. Objek bisa bermanfaat, tetapi penting untuk mengenali bahwa mereka tidak sesuai untuk semuanya. Tidak ada dikotomi; hanya masalah memilih alat yang tepat untuk pekerjaan yang tepat, dan pemrograman fungsional tidak mengharuskan Anda menyerahkan objek. Selain itu, pemrograman fungsional lebih dari sekadar menggunakan fungsi. Ini juga tentang meminimalkan efek samping dan mutasi.
sumber
Saya tidak bisa menjawab pertanyaan itu karena saya tidak pandai bahasa fungsional; tapi saya pikir Anda tidak perlu terlalu khawatir tentang pendekatan selama apa yang Anda miliki berhasil. Dari apa yang saya pahami, selama Anda tidak menambahkan lebih banyak pendengar di masa depan atau tidak mengubah pendengar selama eksekusi, Anda dapat melewati pola Observer di sini.
Saya tidak setuju bahwa pola desain menggantikan "keterbatasan" dalam bahasa OO. Mereka ada untuk memanfaatkan fitur OOP dengan baik. Polimorfisme dan pewarisan adalah fitur, bukan batasan. Pola desain memanfaatkan fitur-fitur ini untuk mempromosikan desain yang fleksibel. Anda dapat membuat program yang benar-benar non-OO dalam OO. Anda dapat, dengan sangat hati-hati, menulis seluruh program yang berisi objek yang tidak memiliki status, meniru FP.
sumber