Pertanyaan Apakah pemrograman fungsional menggantikan pola desain GOF?


Sejak saya mulai belajar F # dan OCaml tahun lalu, saya telah membaca banyak artikel yang menekankan bahwa pola desain (terutama di Jawa) adalah solusi untuk fitur-fitur yang hilang dalam bahasa-bahasa imperatif. Satu artikel yang saya temukan membuat klaim yang cukup kuat:

Kebanyakan orang yang saya temui telah membaca   Buku Pola Desain oleh Geng   Empat. Setiap programmer yang menghargai diri sendiri   akan memberi tahu Anda bahwa buku itu   bahasa agnostik dan polanya   berlaku untuk rekayasa perangkat lunak di   umum, terlepas dari bahasa apa   Kau gunakan. Ini adalah klaim yang mulia.   Sayangnya itu jauh dari   kebenaran.

Bahasa-bahasa fungsional sangat luar biasa   ekspresif. Dalam bahasa fungsional   seseorang tidak membutuhkan pola desain   karena bahasanya mungkin sangat tinggi   tingkat, Anda mengakhiri pemrograman   konsep yang menghilangkan desain   pola bersama-sama.

Fitur utama dari pemrograman fungsional termasuk fungsi sebagai nilai-nilai kelas pertama, currying, nilai-nilai abadi, dll. Tidak tampak jelas bagi saya bahwa pola desain OO mendekati salah satu fitur tersebut.

Selain itu, dalam bahasa fungsional yang mendukung OOP (seperti F # dan OCaml), tampaknya jelas bagi saya bahwa programmer yang menggunakan bahasa ini akan menggunakan pola desain yang sama yang tersedia untuk setiap bahasa OOP lainnya. Faktanya, saat ini saya menggunakan F # dan OCaml setiap hari, dan tidak ada perbedaan mencolok antara pola yang saya gunakan dalam bahasa ini vs. pola yang saya gunakan ketika saya menulis di Java.

Adakah kebenaran atas klaim bahwa pemrograman fungsional menghilangkan kebutuhan untuk pola desain OOP? Jika demikian, dapatkah Anda mengirim atau menautkan ke contoh pola desain OOP yang khas dan ekuivalen fungsionalnya?


941
2017-11-29 20:08


asal


Jawaban:


Posting blog yang Anda kutip melebih-lebihkan klaimnya sedikit. FP tidak menghapuskan kebutuhan untuk pola desain. Istilah "pola desain" tidak banyak digunakan untuk menggambarkan hal yang sama dalam bahasa FP. Tetapi mereka ada. Bahasa fungsional memiliki banyak aturan praktik terbaik dalam bentuk "ketika Anda mengalami masalah X, gunakan kode yang tampak seperti Y", yang pada dasarnya adalah pola desain.

Namun, benar bahwa sebagian besar pola desain OOP-spesifik tidak banyak relevan dalam bahasa fungsional.

Saya tidak berpikir itu harus sangat kontroversial untuk mengatakan bahwa pola desain secara umum hanya ada untuk menambal kekurangan dalam bahasa. Dan jika bahasa lain dapat memecahkan masalah yang sama secara sepele, bahasa lain itu tidak memerlukan pola desain untuk itu. Pengguna bahasa itu mungkin bahkan tidak menyadari bahwa masalahnya ada, karena, yah, itu bukan masalah dalam bahasa itu.

Inilah yang dikatakan Gang Empat tentang masalah ini:

Pemilihan bahasa pemrograman adalah penting karena mempengaruhi sudut pandang seseorang. Pola kami menganggap fitur bahasa Smalltalk / C ++ - level, dan pilihan itu menentukan apa yang dapat dan tidak dapat diimplementasikan dengan mudah. Jika kita mengasumsikan bahasa prosedural, kita mungkin telah memasukkan pola desain yang disebut "Warisan", "Enkapsulasi", dan "Polimorfisme". Demikian pula, beberapa pola kami didukung langsung oleh bahasa berorientasi objek yang kurang umum. CLOS memiliki multi-metode, misalnya, yang mengurangi kebutuhan akan suatu pola seperti Visitor. Bahkan, ada cukup perbedaan antara Smalltalk dan C ++ yang berarti bahwa beberapa pola dapat diekspresikan dengan lebih mudah dalam satu bahasa daripada yang lain. (Lihat Iterator misalnya.)

(Di atas adalah kutipan dari pengantar buku Pola Desain, halaman 4, paragraf 3)

Fitur utama fungsional   pemrograman termasuk fungsi sebagai   nilai-nilai kelas satu, currying,   nilai-nilai abadi, dll. Sepertinya tidak   jelas bagi saya bahwa pola desain OO   mendekati salah satu dari mereka   fitur.

Apa pola perintah, jika bukan perkiraan fungsi kelas satu? :) Dalam bahasa FP, Anda cukup mengirimkan fungsi sebagai argumen ke fungsi lain. Dalam bahasa OOP, Anda harus menyelesaikan fungsi di kelas, yang dapat Anda instantiate dan kemudian meneruskan objek tersebut ke fungsi lainnya. Efeknya sama, tetapi dalam OOP itu disebut pola desain, dan dibutuhkan lebih banyak kode. Dan apa pola pabrik abstrak, jika tidak currying? Berikan parameter ke fungsi sedikit demi sedikit, untuk mengonfigurasi jenis nilai apa yang dikeluarkan ketika Anda akhirnya memanggilnya.

Jadi ya, beberapa pola desain GOF dirender berlebihan dalam bahasa FP, karena alternatif yang lebih kuat dan lebih mudah digunakan ada.

Namun tentu saja masih ada pola desain yang sedang tidak dipecahkan dengan bahasa FP. Apa persamaan FP dari seorang tunggal? (Mengabaikan sesaat lajang biasanya pola yang buruk untuk digunakan)

Dan itu juga berfungsi dua cara. Seperti yang saya katakan, FP memiliki pola desainnya juga, orang-orang biasanya tidak menganggapnya begitu.

Tetapi Anda mungkin telah melintasi monad. Apa itu mereka, jika bukan pola desain untuk "berurusan dengan negara global"? Itu masalah yang sangat sederhana dalam bahasa OOP bahwa tidak ada pola desain yang setara di sana.

Kami tidak membutuhkan pola desain untuk "meningkatkan variabel statis", atau "membaca dari soket itu", karena itu hanya apa yang Anda melakukan.

Dalam bahasa fungsional (murni), efek samping dan keadaan bisa berubah adalah tidak mungkin, kecuali Anda bekerja di sekitarnya dengan "pola desain" monad, atau salah satu metode lain untuk memungkinkan hal yang sama.

Selain itu, dalam bahasa fungsional   yang mendukung OOP (seperti F # dan   OCaml), tampak jelas bagi saya itu   programmer menggunakan bahasa ini   akan menggunakan pola desain yang sama   ditemukan tersedia untuk setiap OOP lainnya   bahasa. Bahkan, saat ini saya menggunakan F #   dan OCaml setiap hari, dan tidak ada   perbedaan mencolok antara   pola yang saya gunakan dalam bahasa ini vs   pola yang saya gunakan saat saya menulis   Jawa.

Mungkin karena Anda masih berpikir imperatif? Banyak orang, setelah berurusan dengan bahasa-bahasa imperatif sepanjang hidup mereka, mengalami kesulitan untuk menyerah pada kebiasaan itu ketika mereka mencoba bahasa fungsional. (Saya telah melihat beberapa usaha yang cukup lucu di F #, di mana secara harfiah setiap fungsi hanya string 'membiarkan' pernyataan, pada dasarnya seolah-olah Anda telah mengambil program C, dan menggantikan semua titik koma dengan 'biarkan'. :))

Tetapi kemungkinan lain mungkin Anda belum menyadari bahwa Anda memecahkan masalah secara sepele yang akan membutuhkan pola desain dalam bahasa OOP.

Saat Anda menggunakan currying, atau meneruskan fungsi sebagai argumen ke yang lain, berhenti dan pikirkan bagaimana Anda akan melakukannya dalam bahasa OOP.

Apakah ada kebenaran atas klaim itu   pemrograman fungsional menghilangkan   perlu untuk pola desain OOP?

Ya. :) Ketika Anda bekerja dalam bahasa FP, Anda tidak lagi membutuhkan pola desain khusus OOP. Tetapi Anda masih memerlukan beberapa pola desain umum, seperti MVC atau hal-hal spesifik non-OOP lainnya, dan Anda memerlukan beberapa "pola desain" khusus FP yang baru. Semua bahasa memiliki kekurangan, dan pola desain biasanya cara kami bekerja di sekitar mereka.

Bagaimanapun, Anda mungkin merasa menarik untuk mencoba tangan Anda di "bersih" FP bahasa, seperti ML (favorit pribadi saya, setidaknya untuk tujuan belajar), atau Haskell, di mana Anda tidak memiliki kruk OOP untuk jatuh kembali ketika Anda sedang menghadapi sesuatu yang baru.


Seperti yang diharapkan, beberapa orang keberatan dengan definisi saya tentang pola desain sebagai "memperbaiki kekurangan dalam bahasa", jadi inilah pembenaran saya: Seperti telah dikatakan, kebanyakan pola desain spesifik untuk satu paradigma pemrograman, atau kadang-kadang bahkan satu bahasa tertentu. Seringkali, mereka memecahkan masalah itu saja ada dalam paradigma itu (Lihat monads untuk FP, atau pabrik abstrak untuk OOP). Mengapa pola pabrik abstrak tidak ada di FP? Karena masalah yang coba dipecahkan tidak ada di sana. Jadi, jika ada masalah dalam bahasa OOP, yang tidak ada dalam bahasa FP, maka jelas itu adalah kekurangan bahasa OOP. Masalahnya dapat dipecahkan, tetapi bahasa Anda tidak melakukannya, tetapi membutuhkan banyak kode boilerplate dari Anda untuk mengatasinya. Idealnya, kami ingin bahasa pemrograman kami dibuat secara ajaib semua masalah hilang. Masalah apa pun yang masih ada pada prinsipnya adalah kekurangan bahasa. ;)


950
2017-11-29 23:06



Adakah kebenaran atas klaim bahwa pemrograman fungsional menghilangkan kebutuhan untuk pola desain OOP?

Pemrograman fungsional tidak sama dengan pemrograman berorientasi obyek. Pola desain berorientasi objek tidak berlaku untuk pemrograman fungsional. Sebaliknya, Anda memiliki pola desain pemrograman fungsional.

Untuk pemrograman fungsional, Anda tidak akan membaca buku-buku pola desain OO, Anda akan membaca buku-buku lain tentang pola desain FP.

bahasa agnostik

Tidak sepenuhnya. Hanya bahasa-agnostik sehubungan dengan bahasa OO. Pola desain tidak berlaku untuk bahasa prosedural sama sekali. Mereka hampir tidak masuk akal dalam konteks desain basis data relasional. Mereka tidak berlaku saat mendesain spreadsheet.

pola desain OOP yang khas dan ekuivalen fungsionalnya?

Di atas seharusnya tidak ada. Itu seperti meminta potongan kode prosedural ditulis ulang sebagai kode OO. Ummm ... Jika saya menerjemahkan Fortran asli (atau C) ke Java, saya belum melakukan apa pun selain menerjemahkannya. Jika saya benar-benar menulis ulang ke dalam paradigma OO, itu tidak akan lagi terlihat seperti Fortran atau C asli - itu akan dikenali.

Tidak ada pemetaan sederhana dari OO Design ke Desain Fungsional. Mereka sangat berbeda cara melihat masalah.

Pemrograman fungsional (seperti semua gaya pemrograman) memiliki pola desain. Database relasional memiliki pola desain, OO memiliki pola desain, pemrograman prosedural memiliki pola desain. Semuanya memiliki pola desain, bahkan arsitektur bangunan.

Pola desain - sebagai konsep - adalah cara membangun yang abadi, terlepas dari teknologi atau domain masalah. Namun, pola desain khusus berlaku untuk domain dan teknologi masalah tertentu.

Setiap orang yang berpikir tentang apa yang mereka lakukan akan mengungkap pola desain.


135
2017-11-29 20:15



Komentar Brian tentang keterkaitan erat antara bahasa dan pola adalah to the point,

Bagian yang hilang dari diskusi ini adalah konsep idiom. Buku Coplien, "Advanced C ++" sangat berpengaruh di sini. Jauh sebelum ia menemukan Christopher Alexander dan Kolom Tanpa Nama (dan Anda tidak dapat berbicara dengan bijaksana tentang pola tanpa membaca Aleksander), ia berbicara tentang pentingnya menguasai idiom dalam benar-benar mempelajari suatu bahasa. Dia menggunakan copy string dalam C sebagai contoh, sementara (* from ++ = * to ++); Anda dapat melihat ini sebagai bandaid untuk fitur bahasa yang hilang (atau fitur perpustakaan), tetapi yang benar-benar penting adalah bahwa itu adalah unit pemikiran yang lebih besar, atau ekspresi, daripada bagian-bagiannya.

Itulah yang pola, dan bahasa, coba lakukan, untuk memungkinkan kita mengekspresikan niat kita lebih ringkas. Semakin kaya unit pemikiran, semakin kompleks pikiran yang dapat Anda ungkapkan. Memiliki kosakata yang kaya dan dibagikan dalam berbagai skala - mulai dari arsitektur sistem hingga bit-bit - memungkinkan kita untuk memiliki percakapan yang lebih cerdas, dan memikirkan apa yang seharusnya kita lakukan.

Kita juga bisa, sebagai individu, belajar. Yang merupakan keseluruhan titik latihan. Kita masing-masing dapat memahami dan menggunakan hal-hal yang kita tidak akan pernah bisa memikirkan diri kita sendiri. Bahasa, kerangka kerja, perpustakaan, pola, idiom dan sebagainya semuanya memiliki tempat mereka dalam berbagi kekayaan intelektual.


40
2018-01-01 20:59



Buku GOF secara eksplisit mengikatkan dirinya pada OOP - judulnya adalah Pola Desain - Elemen Reusable Berorientasi pada objek Perangkat lunak (penekanan saya.)


35
2017-11-24 15:49



Pola Desain dalam Pemrograman Dinamis oleh Peter Norvig memiliki cakupan yang mendalam tentang tema umum ini, meskipun tentang bahasa 'dinamis' alih-alih 'fungsional' (ada tumpang tindih).


32
2017-11-29 20:23



Berikut tautan lain, membahas topik ini: http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

Dalam posting blognya Edward menggambarkan semua 23 pola asli GOF dalam hal Haskell.


24
2017-10-19 08:15



Ketika Anda mencoba untuk melihat ini pada tingkat "pola desain" (secara umum) dan "FP versus OOP", jawaban yang Anda akan temukan akan keruh yang terbaik.

Namun, tingkatkan lebih dalam pada kedua sumbu, dan pertimbangkan pola desain khusus dan fitur bahasa tertentu dan segalanya menjadi lebih jelas.

Jadi, misalnya, beberapa pola tertentu, seperti Pengunjung, Strategi, Perintah, dan Pengamat pasti berubah atau hilang saat menggunakan bahasa dengan tipe data aljabar dan pencocokan pola, penutupan, fungsi kelas satu, dll. Namun beberapa pola lain dari buku GoF masih 'bertahan'.

Secara umum, saya akan mengatakan bahwa, dari waktu ke waktu, pola spesifik sedang dihilangkan oleh fitur bahasa baru (atau hanya meningkat popularitas). Ini adalah cara alami desain bahasa; sebagai bahasa menjadi lebih tinggi tingkat, abstraksi yang sebelumnya hanya bisa disebut dalam buku menggunakan contoh sekarang menjadi aplikasi dari fitur bahasa tertentu atau perpustakaan.

(Selain: ini dia a blog terbaru Saya menulis, yang memiliki tautan lain ke diskusi lebih lanjut tentang FP dan pola desain.)


17
2017-11-29 23:15



Presentasi Norvig menyinggung analisis yang mereka lakukan tentang semua pola GoF, dan mereka mengatakan bahwa 16 dari 23 pola memiliki implementasi yang lebih sederhana dalam bahasa fungsional, atau hanya bagian dari bahasa. Jadi mungkin setidaknya tujuh dari mereka adalah a) sama rumit atau b) tidak hadir dalam bahasa. Sayangnya bagi kami, mereka tidak disebutkan!

Saya pikir sudah jelas bahwa sebagian besar pola "kreasional" atau "struktural" dalam GoF hanyalah trik untuk mendapatkan sistem tipe primitif di Java atau C ++ untuk melakukan apa yang Anda inginkan. Tetapi sisanya layak dipertimbangkan tidak peduli bahasa apa yang Anda programkan.

Salah satunya mungkin Prototipe; sementara itu adalah gagasan mendasar dari JavaScript, itu harus diterapkan dari awal dalam bahasa lain.

Salah satu pola favorit saya adalah pola Null Object: menunjukkan tidak adanya sesuatu sebagai objek yang tidak sesuai dengan apa-apa. Ini mungkin lebih mudah untuk memodelkan dalam bahasa fungsional. Namun, pencapaian sebenarnya adalah pergeseran perspektif.


15
2017-11-30 07:11



Saya akan mengatakan bahwa ketika Anda memiliki bahasa seperti Lisp dengan dukungannya untuk macro, maka Anda dapat membangun Anda abstraksi-abstraksi khusus domain, abstraksi yang sering jauh lebih baik daripada solusi idiom umum.


15
2017-12-16 19:44