Dalam posting blog di F # untuk kesenangan dan keuntungan, dikatakan:
Dalam desain fungsional, sangat penting untuk memisahkan perilaku dari data. Tipe data sederhana dan "bodoh". Dan kemudian secara terpisah, Anda memiliki sejumlah fungsi yang bekerja pada tipe data tersebut.
Ini adalah kebalikan dari desain berorientasi objek, di mana perilaku dan data dimaksudkan untuk digabungkan. Lagipula, itulah kelas sebenarnya. Dalam desain yang benar-benar berorientasi objek, Anda seharusnya hanya memiliki perilaku - data bersifat pribadi dan hanya dapat diakses melalui metode.
Bahkan, dalam OOD, tidak memiliki perilaku yang cukup di sekitar tipe data dianggap sebagai Hal yang Buruk, dan bahkan memiliki nama: " model domain anemik ".
Mengingat bahwa dalam C # kita tampaknya terus meminjam dari F #, dan mencoba untuk menulis lebih banyak kode gaya fungsional; kenapa kita tidak meminjam ide untuk memisahkan data / perilaku, dan bahkan menganggapnya buruk? Apakah hanya karena definisi tidak dengan OOP, atau ada alasan konkret bahwa itu buruk di C # yang karena beberapa alasan tidak berlaku di F # (dan pada kenyataannya, dibalik)?
(Catatan: Saya secara khusus tertarik pada perbedaan dalam C # / F # yang dapat mengubah pendapat tentang apa yang baik / buruk, daripada individu yang mungkin tidak setuju dengan pendapat dalam posting blog).
sumber
Jawaban:
Alasan utama FP bertujuan untuk ini dan C # OOP tidak adalah bahwa dalam FP fokusnya adalah pada transparansi referensial; yaitu, data masuk ke fungsi dan data keluar, tetapi data asli tidak berubah.
Dalam C # OOP ada konsep pendelegasian tanggung jawab di mana Anda mendelegasikan manajemen objek untuk itu, dan karena itu Anda ingin itu mengubah internalnya sendiri.
Dalam FP Anda tidak pernah ingin mengubah nilai-nilai dalam suatu objek, oleh karena itu memiliki fungsi Anda tertanam di objek Anda tidak masuk akal.
Lebih jauh dalam FP Anda memiliki polimorfisme jenis yang lebih tinggi yang memungkinkan fungsi Anda menjadi lebih umum daripada C # OOP. Dengan cara ini Anda dapat menulis fungsi yang berfungsi untuk apa pun
a
, dan karenanya memasukkannya ke dalam blok data tidak masuk akal; yang akan erat beberapa metode sehingga hanya bekerja dengan yang khusus jenis daria
. Perilaku seperti itu baik-baik saja dan umum di C # OOP karena Anda tidak memiliki kemampuan untuk melakukan fungsi abstrak secara umum, tetapi dalam FP itu merupakan tradeoff.Masalah terbesar yang pernah saya lihat dalam model domain anemia di C # OOP adalah Anda berakhir dengan kode duplikat karena Anda memiliki DTO x, dan 4 fungsi berbeda yang melakukan aktivitas f ke DTO x karena 4 orang berbeda tidak melihat implementasi lainnya . Ketika Anda meletakkan metode ini langsung pada DTO x, maka ke-4 orang itu semua melihat implementasi f dan menggunakannya kembali.
Model data anemia dalam C # OOP menggunakan kembali kode penghambat, tetapi ini bukan kasus di FP karena satu fungsi digeneralisasi di berbagai jenis sehingga Anda mendapatkan penggunaan kembali kode yang lebih besar karena fungsi tersebut dapat digunakan dalam banyak skenario daripada fungsi yang Anda gunakan akan menulis untuk DTO tunggal dalam C #.
Seperti yang ditunjukkan dalam komentar , inferensi tipe adalah salah satu manfaat yang diandalkan FP untuk memungkinkan polimorfisme yang signifikan, dan secara khusus Anda dapat melacak ini kembali ke sistem tipe Hindley Milner dengan inferensi tipe Algoritma W; inferensi tipe seperti itu dalam sistem tipe C # OOP dihindari karena waktu kompilasi ketika inferensi berbasis kendala ditambahkan menjadi sangat lama karena diperlukan pencarian yang lengkap, detail di sini: https://stackoverflow.com/questions/3968834/generics-why -cant-the-compiler-infer-the-type-argumen-dalam-hal ini
sumber
Pertanyaan Anda memiliki masalah besar yang akan membatasi kegunaan jawaban yang Anda dapatkan: Anda menyiratkan / menganggap bahwa F # dan FP serupa. FP adalah keluarga besar bahasa termasuk penulisan ulang simbolis, dinamis dan statis. Bahkan di antara bahasa FP yang diketik secara statis ada banyak teknologi berbeda untuk mengekspresikan model domain seperti modul tingkat tinggi di OCaml dan SML (yang tidak ada di F #). F # adalah salah satu dari bahasa fungsional ini tetapi sangat terkenal karena lean dan, khususnya, tidak menyediakan modul tingkat tinggi atau jenis yang lebih tinggi.
Bahkan, saya tidak bisa mulai memberi tahu Anda bagaimana model domain diungkapkan dalam FP. Jawaban lain di sini berbicara sangat spesifik tentang bagaimana hal itu dilakukan di Haskell dan sama sekali tidak berlaku untuk Lisp (ibu dari semua bahasa FP), keluarga bahasa ML atau bahasa fungsional lainnya.
Obat generik dapat dianggap sebagai cara memisahkan data dan perilaku. Generik berasal dari keluarga ML bahasa pemrograman fungsional yang bukan bagian dari OOP. C # memiliki obat generik, tentu saja. Jadi orang dapat berargumentasi bahwa C # perlahan meminjam ide untuk memisahkan data dan perilaku.
Saya percaya OOP didasarkan pada premis yang berbeda secara mendasar dan, akibatnya, tidak memberi Anda alat yang Anda butuhkan untuk memisahkan data dan perilaku. Untuk semua tujuan praktis, Anda memerlukan produk dan jumlah tipe data dan mengirimkannya. Dalam ML ini berarti penyatuan dan pencatatan jenis dan pencocokan pola.
Lihatlah contoh yang saya berikan di sini .
Hati-hati melompat dari OOP ke C #. C # sama sekali tidak puritan tentang OOP seperti bahasa lainnya. NET Framework. Sekarang penuh dengan generik, metode statis dan bahkan lambda.
Kurangnya jenis penyatuan dan pencocokan pola dalam C # membuatnya hampir mustahil untuk dilakukan. Ketika semua yang Anda miliki adalah palu, semuanya tampak seperti paku ...
sumber
Saya pikir dalam aplikasi bisnis Anda sering tidak ingin menyembunyikan data karena pencocokan pola pada nilai yang tidak berubah bagus untuk memastikan bahwa Anda menutupi semua kasus yang mungkin. Tetapi jika Anda menerapkan algoritma atau struktur data yang kompleks, Anda lebih baik menyembunyikan detail implementasi yang mengubah ADT (tipe data aljabar) menjadi ADT (tipe data abstrak).
sumber