Apakah fungsi kelas satu pengganti untuk pola Strategi?

15

The pola desain Strategi sering dianggap sebagai pengganti fungsi kelas dalam bahasa yang kurang mereka.

Jadi misalnya katakan Anda ingin meneruskan fungsionalitas ke objek. Di Jawa Anda harus meneruskan objek objek lain yang merangkum perilaku yang diinginkan. Dalam bahasa seperti Ruby, Anda baru saja melewati fungsi itu sendiri dalam bentuk fungsi anonim.

Namun saya memikirkannya dan memutuskan bahwa mungkin Strategi menawarkan lebih dari sekadar fungsi anonim.

Ini karena suatu objek dapat menahan keadaan yang ada secara independen dari periode ketika metode itu berjalan. Namun fungsi anonim dengan sendirinya hanya dapat menahan keadaan yang tidak ada lagi saat fungsi selesai dieksekusi.

Dalam bahasa berorientasi objek yang mendukung fungsi kelas satu, apakah pola strategi memiliki keunggulan dibandingkan menggunakan fungsi?

Aviv Cohn
sumber
10
"Namun fungsi anonim dengan sendirinya hanya dapat menahan keadaan yang tidak ada lagi saat fungsi selesai dieksekusi.": Ini tidak benar: penutupan dapat menahan keadaan yang hidup di berbagai permintaan yang berbeda.
Giorgio
"Namun fungsi anonim dengan sendirinya hanya dapat menahan keadaan yang tidak ada lagi saat fungsi selesai dieksekusi." : tidak melupakan variabel global, dan setidaknya variabel statis.
gbjbaanb

Jawaban:

13

Ketika bahasa mendukung referensi ke fungsi ( Java tidak sejak versi 8 ), ini sering merupakan alternatif yang baik untuk strategi, karena mereka biasanya mengekspresikan hal yang sama dengan sintaks yang lebih sedikit. Namun, ada beberapa kasus di mana objek nyata dapat bermanfaat.

Antarmuka Strategi dapat memiliki beberapa metode. Mari kita ambil antarmuka RouteFindingStragegysebagai contoh, yang merangkum berbagai algoritma pencarian rute. Itu bisa mendeklarasikan metode seperti

  • Route findShortestRoute(Node start, Node destination)
  • boolean doesRouteExist(Node start, Node destination)
  • Route[] findAllPossibleRoutes(Node start, Node destination)
  • Route findShortestRouteToClosestDestination(Node start, Node[] destinations)
  • Route findTravelingSalesmanRoute(Node[] stations)

yang kemudian semuanya akan diterapkan oleh strategi. Beberapa algoritma pencarian rute mungkin memungkinkan optimasi internal untuk beberapa kasus penggunaan ini dan beberapa lainnya tidak, sehingga implementor dapat memutuskan bagaimana menerapkan masing-masing metode ini.

Kasus lain adalah ketika strategi memiliki kondisi batin. Tentu saja, dalam beberapa bahasa penutupan dapat memiliki kondisi bagian dalam, tetapi ketika kondisi bagian dalam ini menjadi sangat kompleks, seringkali menjadi lebih elegan untuk mempromosikan penutupan ke kelas yang lengkap.

Philipp
sumber
2
"ketika keadaan batin ini menjadi sangat kompleks, seringkali menjadi berguna untuk mempromosikan penutupan ke kelas penuh": Mengapa? Jika kondisi bagian dalam menjadi kompleks, Anda juga dapat memasukkannya ke objek / catatan yang disimpan di dalam penutupan.
Giorgio
1
@Giorgio Tapi kemudian Anda akan memiliki dua entitas sintaks untuk mempertahankan - penutupan dan kelas yang mengelola keadaan internalnya. Jadi kode bisa disederhanakan dengan memindahkan penutupan ke kelas itu. Ini mungkin lebih baik atau mungkin tidak, yang tergantung pada kasus penggunaan yang tepat, bahasa pemrograman dan preferensi pribadi.
Philipp
Tampaknya pandangan yang masuk akal bagi saya.
Giorgio
5

Tidak benar bahwa fungsi anonim hanya dapat menahan status yang tidak ada lagi ketika fungsi selesai dieksekusi.

Ambil contoh berikut dalam Common Lisp:

(defun number-strings (ss)
  (let ((counter 0))
    (mapcar #'(lambda (s) (format nil "~a: ~a" (incf counter) s)) ss)))

Fungsi ini mengambil daftar string dan menambahkan penghitung ke setiap elemen daftar. Jadi, misalnya, memohon

(number-strings '("a" "b" "c"))

memberi

("1: a" "2: b" "3: c")

Fungsinya number-strings internal menggunakan fungsi anonim dengan variabel counteryang menyimpan status (nilai saat ini dari penghitung) yang digunakan kembali setiap kali fungsi dipanggil.

Secara umum, Anda dapat menganggap penutupan sebagai objek dengan hanya satu metode. Atau, objek adalah kumpulan penutupan yang berbagi variabel tertutup yang sama. Jadi saya tidak yakin apakah ada kasus-kasus di mana Anda perlu menggunakan objek alih-alih penutupan: Saya berpendapat bahwa keduanya adalah cara melihat pola yang sama dari perspektif yang berbeda.

Secara khusus, pola strategi memerlukan objek dengan hanya satu metode, jadi penutupan harus melakukan pekerjaan. Tapi, seperti yang diamati oleh Philipp dalam jawabannya, tergantung pada keadaan (keadaan kompleks) dan bahasa pemrograman Anda mungkin mendapatkan solusi yang lebih elegan dengan menggunakan objek.

Giorgio
sumber
Jadi dalam bahasa yang mendukung fungsi kelas satu sebagai penutup, apakah Anda masih menggunakan Strategi 'klasik'?
Aviv Cohn
1
Saya cenderung setuju dengan Philipp: itu tergantung pada bahasa dan preferensi pribadi. Saya akan selalu memilih pendekatan yang membuat notasi sesederhana mungkin. Sebagai contoh, di Lisp saya bisa mendefinisikan keadaan saya sebagai daftar variabel melalui a letdan kemudian menentukan penutupan saya di dalamnya. Pada dasarnya, saya akan mendefinisikan objek dengan satu metode dengan cepat. Dalam bahasa lain (misalnya Java), mungkin lebih mudah (secara sintaksis lebih sederhana) untuk mendefinisikan objek yang tepat untuk menahan status. Jadi, saya akan memutuskan dari kasus ke kasus.
Giorgio
1

Hanya karena dua desain dapat menyelesaikan masalah yang sama tidak berarti keduanya merupakan pengganti langsung satu sama lain.

Jika Anda perlu melacak status dalam program fungsional, Anda tidak bermutasi variabel tertutup, bahkan jika bahasa memungkinkan. Anda mengatur untuk memanggil fungsi yang mengambil dalam satu negara sebagai argumen dan mengembalikan negara baru sebagai nilai pengembaliannya.

Arsitektur Anda akan terlihat sangat berbeda, tetapi Anda akan mencapai tujuan yang sama. Jangan mencoba memaksakan pola paradigma satu secara langsung ke yang lain.

Karl Bielefeldt
sumber
"Jika Anda perlu melacak status dalam program fungsional, Anda tidak bermutasi variabel tertutup, bahkan jika bahasa memungkinkan.": Saya penggemar gaya fungsional murni dan saya setuju dengan saran Anda. Di sisi lain, penutupan bukan hanya konstruksi fungsional, apalagi fungsional murni. Gagasan untuk menutup variabel dari konteks leksikal adalah ortogonal untuk transparansi referensi / kekekalan.
Giorgio
Maaf, tapi saya tidak bisa mengikuti argumentasi Anda. Apa hubungan penanganan negara dengan pemrograman murni yang berhubungan dengan pertanyaan yang ada?
Philipp
1
Intinya adalah jika Anda menggunakan satu bagian dari paradigma fungsional, seperti fungsi kelas satu, jangan kaget jika Anda perlu menarik bagian-bagian lain dari paradigma untuk membuatnya bekerja dengan lancar.
Karl Bielefeldt
1

Strategi adalah sebuah konsep , resep yang berguna untuk memecahkan masalah tertentu yang berulang. Ini bukan konstruksi bahasa, juga bukan tentang salah satu bentuk implementasi . Penutupan dapat digunakan untuk menerapkan Strategi satu hari dan Pengamat pada hari berikutnya.

The Istilah Strategi sebagian besar berguna dalam percakapan dengan programmer lain untuk ringkas mengungkapkan maksud Anda. Tidak ada yang ajaib tentang itu.

idoby
sumber
2
Pertanyaannya secara spesifik menyebutkan pola desain strategi yang memiliki struktur kelas tertentu. Arti lain dari "strategi" sebagai rencana tindakan yang dimaksudkan untuk mencapai tujuan tertentu tidak akurat dalam konteks ini.
Saya cenderung setuju dengan @Smanman. Anda yakin berbicara tentang pola strategi ?
Rowan Freeman
1
@Snowman, bahkan halaman yang Anda tautkan tidak menyatakan dengan tepat bagaimana pola ini harus diterapkan, alih-alih mereka memberikan contoh dalam bahasa tertentu, tetapi tidak ada dalam diagram UML yang mengatakan bahwa saya perlu menggunakan pewarisan C ++, antarmuka Java atau blok Ruby . Jadi saya tidak setuju dengan analisis Anda.
idoby