Desain dalam bahasa "campuran": desain berorientasi objek atau pemrograman fungsional?

11

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?

Lorenzo Dematté
sumber
Bagaimana dengan Aktor?
kiritsuku
Lupakan kelas dan semua hal-hal yang tidak berguna OOPish. Anda lebih baik berpikir dalam hal modul sebagai gantinya (lihat bahasa SML dan OCaml untuk inspirasi).
SK-logic
@Antoras Jika Anda dapat membandingkan dengan pendekatan berdasarkan Aktor, itu akan lebih dari menyambut :)
Lorenzo Dematté
2
@ dema80, OCaml adalah multi-paradigma sempurna. Modul tidak terkait dengan pemrograman fungsional sama sekali. Ada sistem modul canggih di Ada murni imperatif, misalnya. Dan semua ketenaran OOP yang diperoleh harus benar-benar masuk ke modul - semua yang baik dalam OOP hanyalah berbagai bentuk simulasi fungsi modul. Anda dapat benar-benar melupakan semua kelas itu dan menggunakan sintaksnya untuk mengekspresikan modul, berpikir dalam hal modul, bukan OOP. Btw., Itulah yang dilakukan Microsoft dengan mscorlib mereka - tidak banyak OOP di sana, hanya modul dan ruang nama.
SK-logic
1
Saya pikir pertanyaan yang lebih baik adalah "Apakah ada kejelasan atau organisasi yang Anda kehilangan dengan melakukannya dengan cara FP?"
djechlin

Jawaban:

0

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.

Filip Dupanović
sumber
Saya pikir jawaban ini agak salah kaprah. Pemrograman fungsional bukanlah pemrograman (hanya dengan) fungsi. Pemrograman fungsional menggunakan abstraksi juga, jadi tidak ada dikotomi di sini.
Doval
"Komposisi atau warisan, di mana Anda akan memiliki sedikit lebih banyak kebebasan untuk menggunakan kembali dan memperluas perilaku yang ada" Anda berbicara seperti ini TIDAK ADA salah satu manfaat inti dari FP murni. modularitas, composability, dan reuseability terjadi secara alami ketika Anda membuat kode secara fungsional, ini bukan "OOP thing"
sara
@ FilipDupanović Saya merujuk untuk menggunakan kembali dan memperluas kode yang ada. fungsi murni mungkin adalah hal yang paling mudah dikompilasi dalam semua pemrograman. Anda menulis seolah-olah Anda tidak dapat mengelola kompleksitas dalam lingkungan fungsional murni. mengelola kompleksitas dengan menyusun bagian-bagian sederhana menjadi bagian-bagian yang lebih besar tetapi tetap sederhana dan buram adalah inti dari FP, dan banyak orang akan berpendapat bahwa cara ini lebih baik daripada OOP. Saya tidak setuju dengan dikotomi antara "fungsional satu-liner yang tidak skala VS OOP padat yang skala tidak ada masalah" yang Anda kemukakan.
sara
Anda mengatakan bahwa FP lebih rendah ketika membuat dan menggunakan kembali kode, dan bahwa ketika aplikasi tumbuh lebih kompleks, OOP akan lebih atau kurang selalu menjadi "lebih baik". Saya mengklaim ini benar-benar salah dan menyesatkan, jadi saya pikir itu menuntut downvote. Apakah itu benar-benar "zealotry murni"? Saya tidak akan membahas ini lebih lanjut di sini karena komentar bukan untuk diskusi panjang seperti ini.
Sara
5

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.

DeadMG
sumber
Saya setuju dan memiliki perasaan yang sama.
Lorenzo Dematté
Saya setuju dan memiliki perasaan yang sama. Tapi saya agak "curang" dengan kode fungsional saya: dalam kasus saya adalah semua yang saya butuhkan, tetapi bagaimana jika saya perlu menambah dan menghapus "pengamat"? Saya mengedit pertanyaan saya
Lorenzo Dematté
5

"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 IItemObserverhanya 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.

Doval
sumber
+1 untuk (IMO) jawaban yang bagus. Juga, terima kasih atas tautannya ke koran: Saya telah membacanya beberapa waktu lalu dan kemudian kehilangannya. Sekarang saya sudah menemukannya lagi.
Giorgio
-1

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.

DPD
sumber
1
"Anda dapat, dengan sangat hati-hati, menulis seluruh program yang berisi objek yang tidak memiliki status, meniru FP.", Tentu saja, dan melalui disiplin Anda dapat melakukan hal yang sama dalam bahasa imperatif juga. :) Secara umum, saya tidak berpikir desain patters sebagai sesuatu untuk menebus keterbatasan, tetapi mempertimbangkan kasus pola Pengunjung ..
Lorenzo Dematté
Juga, saya tidak peduli dengan kode: namun, saya ingin berkonfrontasi dengan sesama programmer tentang pendekatan (menurut pemahaman saya, inilah tujuan programer.
Seandainya
Setiap kali Anda menemukan pola berulang, itu hanyalah indikasi keterbatasan parah dari bahasa Anda dan kerangka kerja pemodelan. Tidak akan ada pola sama sekali di dunia yang ideal.
SK-logic
@ SK-logic: Sayangnya dunia ini tidak ideal, dan dunia nyata memiliki pola. Itulah sebabnya bahasa OO memiliki warisan, untuk menerapkan kode berulang tanpa harus menulis ulang mereka lagi. Objek dunia nyata memiliki keadaan, itulah sebabnya ada pola Negara
DPD
1
@ SK-logic: Saya sangat menyadari bahwa beberapa bahasa dapat diprogram, dan beberapa mengizinkan penerapan efek dari sistem tipe juga. Maksud saya adalah, seperti "OOP", "pola" adalah istilah yang disalahpahami. Pola adalah sesuatu yang terus muncul kembali dalam bentuk yang sama tetapi berbeda , yang tidak mengakui solusi yang seragam . Kadang-kadang Anda dapat membuat quasirepetitions tersebut hilang - banyak metode membuat Pengunjung / pengiriman ganda menjadi berlebihan. Itu tidak menyiratkan "semua pola adalah tanda-tanda kekurangan", karena itu berarti dunia nyata kurang. Pola berasal dari arsitektur , bukan perangkat lunak.
Frank Shearar