Saya terus melihat referensi ke pola pengunjung di blog tetapi saya harus mengakui, saya hanya tidak mengerti. Saya membaca artikel wikipedia untuk polanya dan saya memahami mekanismenya, tetapi saya masih bingung kapan saya akan menggunakannya.
Sebagai seseorang yang baru-baru ini benar - benar mendapatkan pola dekorator dan sekarang melihat kegunaan untuk itu di mana-mana saya ingin dapat benar-benar memahami secara intuitif pola yang tampaknya berguna ini juga.
design-patterns
visitor-pattern
George Mauer
sumber
sumber
Jawaban:
Saya tidak terlalu mengenal pola Pengunjung. Mari kita lihat apakah saya benar. Misalkan Anda memiliki hierarki hewan
(Misalkan itu adalah hierarki yang kompleks dengan antarmuka yang mapan.)
Sekarang kami ingin menambahkan operasi baru ke hierarki, yaitu kami ingin setiap hewan membuat suaranya. Sejauh hierarkinya sesederhana ini, Anda dapat melakukannya dengan polimorfisme langsung:
Tetapi melanjutkan dengan cara ini, setiap kali Anda ingin menambahkan operasi Anda harus memodifikasi antarmuka untuk setiap kelas hirarki. Sekarang, anggaplah Anda puas dengan antarmuka asli, dan bahwa Anda ingin membuat modifikasi sesedikit mungkin untuk itu.
Pola Pengunjung memungkinkan Anda untuk memindahkan setiap operasi baru di kelas yang sesuai, dan Anda perlu memperluas antarmuka hierarki hanya sekali. Ayo lakukan. Pertama, kami mendefinisikan operasi abstrak (kelas "Pengunjung" di GoF ) yang memiliki metode untuk setiap kelas dalam hierarki:
Kemudian, kami memodifikasi hierarki untuk menerima operasi baru:
Akhirnya, kami menerapkan operasi yang sebenarnya, tanpa memodifikasi baik Kucing maupun Anjing :
Sekarang Anda memiliki cara untuk menambahkan operasi tanpa memodifikasi hierarki lagi. Inilah cara kerjanya:
sumber
letsDo(Operation *v)
membutuhkan pointer.theSound.hereIsACat(c)
akan melakukan pekerjaan itu, bagaimana Anda membenarkan untuk semua biaya overhead yang diperkenalkan oleh pola? pengiriman ganda adalah pembenaran.Alasan untuk kebingungan Anda mungkin adalah bahwa Pengunjung adalah keliru fatal. Banyak (menonjol 1 !) Programmer telah tersandung masalah ini. Apa yang sebenarnya dilakukannya adalah menerapkan pengiriman ganda dalam bahasa yang tidak mendukungnya secara asli (kebanyakan dari mereka tidak).
1) Contoh favorit saya adalah Scott Meyers, penulis terkenal “Effective C ++”, yang menyebut ini salah satu C ++ aha paling penting! saat-saat yang pernah ada .
sumber
switch
:switch
hard-kode pengambilan keputusan di sisi client (duplikasi kode) dan tidak menawarkan memeriksa jenis statis ( periksa kelengkapan dan perbedaan kasus, dll.). Pola pengunjung diverifikasi oleh pemeriksa tipe, dan biasanya membuat kode klien lebih sederhana.virtual
fitur seperti sangat berguna dalam bahasa pemrograman modern - mereka adalah blok bangunan dasar program yang dapat dikembangkan - menurut saya cara c (sakelar bersarang atau pencocokan pola, dll. Tergantung pada bahasa pilihan Anda) adalah jauh lebih bersih dalam kode yang tidak perlu diperpanjang dan saya sangat terkejut melihat gaya ini dalam perangkat lunak yang rumit seperti prover 9. Lebih penting lagi bahasa apa pun yang ingin memberikan ekstensibilitas mungkin harus mengakomodasi pola pengiriman yang lebih baik daripada pengiriman tunggal rekursif (yaitu pengunjung).Semua orang di sini benar, tetapi saya pikir gagal untuk menjawab "kapan". Pertama, dari Pola Desain:
Sekarang, mari kita pikirkan hirarki kelas yang sederhana. Saya memiliki kelas 1, 2, 3 dan 4 dan metode A, B, C dan D. Lay out seperti dalam spreadsheet: kelas adalah garis dan metode adalah kolom.
Sekarang, desain Berorientasi Objek menganggap Anda lebih mungkin untuk mengembangkan kelas baru daripada metode baru, sehingga menambahkan lebih banyak garis, sehingga untuk berbicara, lebih mudah. Anda cukup menambahkan kelas baru, menentukan apa yang berbeda di kelas itu, dan mewarisi sisanya.
Namun, kadang-kadang, kelasnya relatif statis, tetapi Anda perlu menambahkan lebih banyak metode - menambah kolom. Cara standar dalam desain OO adalah menambahkan metode seperti itu ke semua kelas, yang bisa mahal. Pola Pengunjung memudahkan ini.
Ngomong-ngomong, ini adalah masalah yang ingin diselesaikan oleh pola Scala.
sumber
The Visitor pola desain bekerja dengan sangat baik untuk "recursive" struktur seperti pohon direktori, struktur XML, atau garis besar dokumen.
Objek Pengunjung mengunjungi setiap node dalam struktur rekursif: setiap direktori, setiap tag XML, apa pun. Objek Pengunjung tidak melewati struktur. Sebaliknya, metode Pengunjung diterapkan ke setiap simpul struktur.
Berikut adalah struktur simpul rekursif khas. Bisa berupa direktori atau tag XML. [Jika Anda orang Jawa, bayangkan banyak metode tambahan untuk membangun dan memelihara daftar anak-anak.]
The
visit
Metode berlaku objek pengunjung ke setiap node dalam struktur. Dalam hal ini, ini adalah pengunjung top-down. Anda dapat mengubah strukturvisit
metode untuk melakukan bottom-up atau pemesanan lainnya.Ini adalah superclass untuk pengunjung. Ini digunakan oleh
visit
metode. Itu "tiba di" setiap node dalam struktur. Karenavisit
metode ini memanggilup
dandown
, pengunjung dapat melacak kedalamannya.Subclass dapat melakukan hal-hal seperti menghitung node di setiap level dan mengumpulkan daftar node, menghasilkan jalur yang bagus, nomor bagian hierarkis.
Ini sebuah aplikasi. Itu membangun struktur pohon
someTree
,. Ini menciptakanVisitor
,dumpNodes
.Kemudian itu berlaku
dumpNodes
untuk pohon itu. ThedumpNode
objek akan "mengunjungi" setiap node di pohon.visit
Algoritma TreeNode akan memastikan bahwa setiap TreeNode digunakan sebagai argumen untuk metode PengunjungarrivedAt
.sumber
Salah satu cara untuk melihatnya adalah bahwa pola pengunjung adalah cara untuk membiarkan klien Anda menambahkan metode tambahan ke semua kelas Anda dalam hierarki kelas tertentu.
Ini berguna ketika Anda memiliki hierarki kelas yang cukup stabil, tetapi Anda telah mengubah persyaratan tentang apa yang perlu dilakukan dengan hierarki itu.
Contoh klasik adalah untuk kompiler dan sejenisnya. Abstract Syntax Tree (AST) dapat secara akurat mendefinisikan struktur bahasa pemrograman, tetapi operasi yang mungkin ingin Anda lakukan pada AST akan berubah seiring kemajuan proyek Anda: generator kode, printer cantik, debugger, analisis metrik kompleksitas.
Tanpa Pola Pengunjung, setiap kali pengembang ingin menambahkan fitur baru, mereka perlu menambahkan metode itu ke setiap fitur di kelas dasar. Ini sangat sulit ketika kelas dasar muncul di perpustakaan yang terpisah, atau diproduksi oleh tim yang terpisah.
(Saya telah mendengarnya berpendapat bahwa pola Pengunjung bertentangan dengan praktik OO yang baik, karena memindahkan operasi data menjauh dari data. Pola Pengunjung berguna dalam situasi yang tepat ketika praktik OO normal gagal.)
sumber
Setidaknya ada tiga alasan yang sangat baik untuk menggunakan Pola Pengunjung:
Mengurangi proliferasi kode yang hanya sedikit berbeda ketika struktur data berubah.
Menerapkan perhitungan yang sama untuk beberapa struktur data, tanpa mengubah kode yang mengimplementasikan perhitungan.
Tambahkan informasi ke pustaka lawas tanpa mengubah kode lawas.
Silakan lihat artikel yang saya tulis tentang ini .
sumber
Seperti yang ditunjukkan oleh Konrad Rudolph, sangat cocok untuk kasus-kasus di mana kita perlu pengiriman ganda
Berikut adalah contoh untuk menunjukkan situasi di mana kami perlu pengiriman ganda & bagaimana pengunjung membantu kami melakukannya.
Contoh:
Katakanlah saya memiliki 3 jenis perangkat seluler - iPhone, Android, Windows Mobile.
Ketiga perangkat ini memiliki radio Bluetooth yang terpasang di dalamnya.
Mari kita asumsikan bahwa radio gigi biru dapat berasal dari 2 OEM terpisah - Intel & Broadcom.
Hanya untuk membuat contoh yang relevan untuk diskusi kita, mari kita asumsikan juga bahwa API yang diekspos oleh radio Intel berbeda dari yang diekspos oleh radio Broadcom.
Beginilah tampilan kelas saya -
Sekarang, saya ingin memperkenalkan operasi - Mengaktifkan Bluetooth di perangkat seluler.
Tanda tangannya fungsinya harus seperti ini -
Jadi tergantung pada jenis perangkat yang Tepat dan Tergantung pada jenis radio Bluetooth yang tepat , itu dapat diaktifkan dengan memanggil langkah-langkah atau algoritma yang sesuai .
Pada prinsipnya, itu menjadi matriks 3 x 2, di mana-dalam saya mencoba untuk vektor operasi yang tepat tergantung pada jenis objek yang tepat yang terlibat.
Perilaku polimorfik tergantung pada jenis kedua argumen.
Sekarang, pola Pengunjung dapat diterapkan untuk masalah ini. Inspirasi berasal dari halaman Wikipedia yang menyatakan - “Pada dasarnya, pengunjung memungkinkan seseorang untuk menambahkan fungsi virtual baru ke keluarga kelas tanpa memodifikasi kelas sendiri; alih-alih, seseorang membuat kelas pengunjung yang mengimplementasikan semua spesialisasi yang sesuai dari fungsi virtual. Pengunjung mengambil referensi contoh sebagai input, dan mengimplementasikan tujuan melalui pengiriman ganda. "
Pengiriman ganda adalah suatu keharusan di sini karena matriks 3x2
Beginilah tampilan pengaturannya -
Saya menulis contoh untuk menjawab pertanyaan lain, kode & penjelasannya disebutkan di sini .
sumber
Saya merasa lebih mudah dalam tautan berikut:
Dalam http://www.remondo.net/visitor-pattern-example-csharp/ saya menemukan contoh yang menunjukkan contoh tiruan yang menunjukkan apa manfaat dari pola pengunjung. Di sini Anda memiliki kelas wadah yang berbeda untuk
Pill
:Seperti yang Anda lihat di atas, Anda
BilsterPack
mengandung pasangan Pil sehingga Anda perlu mengalikan jumlah pasangan dengan 2. Juga, Anda mungkin memperhatikan bahwaBottle
penggunaanunit
yang merupakan tipe data berbeda dan perlu dilemparkan.Jadi dalam metode utama Anda dapat menghitung jumlah pil menggunakan kode berikut:
Perhatikan bahwa kode di atas melanggar
Single Responsibility Principle
. Itu berarti Anda harus mengubah kode metode utama jika Anda menambahkan jenis wadah baru. Juga beralih lebih lama adalah praktik yang buruk.Jadi dengan memperkenalkan kode berikut:
Anda memindahkan tanggung jawab menghitung jumlah
Pill
s ke kelas yang disebutPillCountVisitor
(Dan kami menghapus pernyataan kasus sakelar). Itu artinya setiap kali Anda perlu menambahkan wadah pil jenis baru, Anda hanya perlu mengubahPillCountVisitor
kelas. Juga perhatikanIVisitor
antarmuka umum untuk digunakan dalam skenario lain.Dengan menambahkan metode Terima ke kelas wadah pil:
kami mengizinkan pengunjung untuk mengunjungi kelas wadah pil.
Pada akhirnya kami menghitung jumlah pil menggunakan kode berikut:
Itu artinya: Setiap wadah pil memungkinkan
PillCountVisitor
pengunjung untuk melihat jumlah pil mereka. Dia tahu bagaimana cara menghitung pil Anda.Pada
visitor.Count
memiliki nilai pil.Dalam http://butunclebob.com/ArticleS.UncleBob.IuseVisitor Anda melihat skenario nyata di mana Anda tidak dapat menggunakan polimorfisme (jawabannya) untuk mengikuti Prinsip Tanggung Jawab Tunggal. Bahkan di:
yang
reportQtdHoursAndPay
metode adalah untuk pelaporan dan representasi dan ini melanggar Tanggung Jawab Single Prinsip. Jadi lebih baik menggunakan pola pengunjung untuk mengatasi masalah tersebut.sumber
Pengiriman ganda hanyalah salah satu alasan antara lain untuk menggunakan pola ini .
Tetapi perhatikan bahwa ini adalah cara tunggal untuk menerapkan pengiriman ganda atau lebih dalam bahasa yang menggunakan paradigma pengiriman tunggal.
Berikut adalah alasan untuk menggunakan polanya:
1) Kami ingin mendefinisikan operasi baru tanpa mengubah model setiap kali karena model tidak sering berubah karena operasi sering berubah.
2) Kami tidak ingin memadukan model dan perilaku karena kami ingin memiliki model yang dapat digunakan kembali dalam banyak aplikasi atau kami ingin memiliki model yang dapat diperluas yang memungkinkan kelas klien untuk mendefinisikan perilaku mereka dengan kelas mereka sendiri.
3) Kami memiliki operasi umum yang bergantung pada jenis konkret model tetapi kami tidak ingin menerapkan logika di setiap subkelas karena akan meledak logika umum di beberapa kelas dan di banyak tempat .
4) Kami menggunakan desain model domain dan kelas model hierarki yang sama melakukan terlalu banyak hal berbeda yang dapat dikumpulkan di tempat lain .
5) Kami membutuhkan pengiriman ganda .
Kami memiliki variabel yang dideklarasikan dengan tipe antarmuka dan kami ingin dapat memprosesnya berdasarkan tipe runtime mereka ... tentu saja tanpa menggunakan
if (myObj instanceof Foo) {}
atau trik apa pun.Idenya adalah misalnya untuk meneruskan variabel-variabel ini ke metode yang mendeklarasikan tipe konkret antarmuka sebagai parameter untuk menerapkan pemrosesan tertentu. Cara melakukan ini tidak dimungkinkan di luar kotak dengan bahasa bergantung pada pengiriman tunggal karena yang dipilih dipanggil saat runtime hanya bergantung pada jenis runtime penerima.
Perhatikan bahwa di Jawa, metode (tanda tangan) untuk memanggil dipilih pada waktu kompilasi dan itu tergantung pada tipe parameter yang dideklarasikan, bukan tipe runtime mereka.
Poin terakhir yang menjadi alasan untuk menggunakan pengunjung juga merupakan konsekuensi karena ketika Anda menerapkan pengunjung (tentu saja untuk bahasa yang tidak mendukung pengiriman ganda), Anda perlu memperkenalkan implementasi pengiriman ganda.
Perhatikan bahwa traversal elemen (iterasi) untuk menerapkan pengunjung pada masing-masing bukan alasan untuk menggunakan pola.
Anda menggunakan pola karena Anda membagi model dan pemrosesan.
Dan dengan menggunakan polanya, Anda mendapat manfaat selain dari kemampuan iterator.
Kemampuan ini sangat kuat dan melampaui iterasi pada tipe umum dengan metode spesifik sebagaimana
accept()
metode generik.Ini adalah kasus penggunaan khusus. Jadi saya akan meletakkannya di satu sisi.
Contoh di Jawa
Saya akan mengilustrasikan nilai tambah dari pola dengan contoh catur di mana kami ingin mendefinisikan pemrosesan saat pemain meminta bagian bergerak.
Tanpa penggunaan pola pengunjung, kita bisa mendefinisikan perilaku pemindahan potongan langsung dalam subkelas potongan.
Misalnya kita dapat memiliki
Piece
antarmuka seperti:Setiap subkelas Piece akan mengimplementasikannya seperti:
Dan hal yang sama untuk semua subclass Sepotong.
Berikut adalah diagram diagram yang menggambarkan desain ini:
Pendekatan ini menghadirkan tiga kelemahan penting:
- perilaku seperti
performMove()
ataucomputeIfKingCheck()
akan sangat mungkin menggunakan logika umum.Misalnya apa pun yang konkret
Piece
,performMove()
akhirnya akan mengatur potongan saat ini ke lokasi tertentu dan berpotensi mengambil potongan lawan.Memisahkan perilaku terkait dalam beberapa kelas alih-alih mengumpulkan mereka dengan cara tertentu merupakan pola tanggung jawab tunggal. Membuat pemeliharaan mereka lebih sulit.
- Memproses sebagaimana
checkMoveValidity()
seharusnya tidak menjadi sesuatu yangPiece
dapat dilihat atau diubah oleh subclass.Ini adalah pemeriksaan yang melampaui tindakan manusia atau komputer. Pemeriksaan ini dilakukan pada setiap tindakan yang diminta oleh pemain untuk memastikan bahwa kepindahan potongan yang diminta valid.
Jadi kami bahkan tidak ingin memberikan itu di
Piece
antarmuka.- Dalam permainan catur yang menantang bagi pengembang bot, umumnya aplikasi menyediakan API standar (
Piece
antarmuka, subkelas, Dewan, perilaku umum, dll ...) dan memungkinkan pengembang memperkaya strategi bot mereka.Untuk dapat melakukan itu, kami harus mengusulkan model di mana data dan perilaku tidak digabungkan secara erat dalam
Piece
implementasi.Jadi mari kita pergi menggunakan pola pengunjung!
Kami memiliki dua jenis struktur:
- kelas model yang menerima untuk dikunjungi (bagian)
- pengunjung yang mengunjungi mereka (operasi yang bergerak)
Berikut adalah diagram kelas yang menggambarkan polanya:
Di bagian atas kami memiliki pengunjung dan di bagian bawah kami memiliki kelas model.
Berikut adalah
PieceMovingVisitor
antarmuka (perilaku yang ditentukan untuk setiap jenisPiece
):Sepotong didefinisikan sekarang:
Metode utamanya adalah:
Ini memberikan pengiriman pertama: doa berdasarkan
Piece
penerima.Pada waktu kompilasi, metode terikat ke
accept()
metode antarmuka Piece dan pada saat runtime, metode terikat akan dipanggil padaPiece
kelas runtime .Dan itu adalah
accept()
implementasi metode yang akan melakukan pengiriman kedua.Memang, setiap
Piece
subclass yang ingin dikunjungi olehPieceMovingVisitor
objek memanggilPieceMovingVisitor.visit()
metode dengan melewati sebagai argumen itu sendiri.Dengan cara ini, kompiler batas segera setelah waktu kompilasi, tipe parameter yang dideklarasikan dengan tipe beton.
Ada pengiriman kedua.
Berikut adalah
Bishop
subclass yang menggambarkan bahwa:Dan inilah contoh penggunaannya:
Kerugian pengunjung
Pola Pengunjung adalah pola yang sangat kuat tetapi juga memiliki beberapa batasan penting yang harus Anda pertimbangkan sebelum menggunakannya.
1) Risiko untuk mengurangi / menghancurkan enkapsulasi
Dalam beberapa jenis operasi, pola pengunjung dapat mengurangi atau menghancurkan enkapsulasi objek domain.
Sebagai contoh, karena
MovePerformingVisitor
kelas perlu mengatur koordinat potongan aktual,Piece
antarmuka harus menyediakan cara untuk melakukan itu:Tanggung jawab
Piece
perubahan koordinat sekarang terbuka untuk kelas selainPiece
subkelas.Memindahkan pemrosesan yang dilakukan oleh pengunjung di
Piece
subkelas juga bukan pilihan.Itu memang akan membuat masalah lain karena
Piece.accept()
menerima implementasi pengunjung. Ia tidak tahu apa yang dilakukan pengunjung dan karenanya tidak tahu tentang apakah dan bagaimana mengubah keadaan Sepotong.Cara untuk mengidentifikasi pengunjung adalah dengan melakukan pemrosesan pos
Piece.accept()
sesuai dengan implementasi pengunjung. Ini akan menjadi ide yang sangat buruk karena akan membuat sambungan tinggi antara implementasi Pengunjung dan subkelas Sepotong dan selain itu mungkin akan perlu menggunakan trikgetClass()
,instanceof
atau penanda apa pun yang mengidentifikasi implementasi Pengunjung.2) Persyaratan untuk mengubah model
Berlawanan dengan beberapa pola desain perilaku lainnya seperti
Decorator
misalnya, pola pengunjung mengganggu.Kita memang perlu memodifikasi kelas penerima awal untuk menyediakan
accept()
metode untuk menerima untuk dikunjungi.Kami tidak memiliki masalah untuk
Piece
dan subkelasnya karena ini adalah kelas kami .Di kelas bawaan atau pihak ketiga, banyak hal tidak mudah.
Kita perlu membungkus atau mewarisi (jika kita bisa) mereka untuk menambahkan
accept()
metode.3) Indirections
Pola ini menciptakan banyak tipuan.
Pengiriman ganda berarti dua doa alih-alih satu:
Dan kita dapat memiliki tipuan tambahan saat pengunjung mengubah status objek yang dikunjungi.
Itu mungkin terlihat seperti sebuah siklus:
sumber
Cay Horstmann memiliki contoh yang bagus tentang tempat menerapkan Pengunjung dalam buku OO Desain dan pola-nya . Dia merangkum masalah:
Alasannya tidak mudah adalah karena operasi ditambahkan dalam kelas struktur itu sendiri. Misalnya, bayangkan Anda memiliki Sistem File:
Berikut adalah beberapa operasi (fungsi) yang mungkin ingin kami terapkan dengan struktur ini:
Anda bisa menambahkan fungsi ke setiap kelas di FileSystem untuk mengimplementasikan operasi (dan orang-orang telah melakukan ini di masa lalu karena sangat jelas bagaimana melakukannya). Masalahnya adalah bahwa setiap kali Anda menambahkan fungsionalitas baru (baris "dll." Di atas), Anda mungkin perlu menambahkan lebih banyak metode ke kelas struktur. Pada titik tertentu, setelah beberapa operasi yang Anda tambahkan ke perangkat lunak Anda, metode di kelas-kelas itu tidak masuk akal lagi dalam hal kohesi fungsional kelas '. Misalnya, Anda memiliki
FileNode
yang memiliki metodecalculateFileColorForFunctionABC()
untuk menerapkan fungsi visualisasi terbaru pada sistem file.Pola Pengunjung (seperti banyak pola desain) lahir dari rasa sakit dan penderitaan pengembang yang tahu ada cara yang lebih baik untuk memungkinkan kode mereka untuk berubah tanpa memerlukan banyak perubahan di mana-mana dan juga menghormati prinsip-prinsip desain yang baik (kohesi tinggi, kopling rendah ). Menurut saya sulit memahami manfaat dari banyak pola sampai Anda merasakan sakit itu. Menjelaskan rasa sakit (seperti yang kami coba lakukan di atas dengan fungsionalitas "dll." Yang ditambahkan) membutuhkan ruang dalam penjelasan dan merupakan pengalih perhatian. Memahami pola sulit karena alasan ini.
Pengunjung memungkinkan kita untuk memisahkan fungsi pada struktur data (misalnya,
FileSystemNodes
) dari struktur data itu sendiri. Pola ini memungkinkan desain untuk menghormati kohesi - kelas struktur data lebih sederhana (mereka memiliki metode yang lebih sedikit) dan juga fungsionalitas dienkapsulasi ke dalamVisitor
implementasi. Ini dilakukan melalui pengiriman ganda (yang merupakan bagian rumit dari pola): menggunakanaccept()
metode di kelas struktur danvisitX()
metode di kelas Pengunjung (fungsi):Struktur ini memungkinkan kami untuk menambahkan fungsionalitas baru yang bekerja pada struktur sebagai Pengunjung nyata (tanpa mengubah kelas struktur).
Misalnya,
PrintNameVisitor
yang mengimplementasikan fungsi daftar direktori, danPrintSizeVisitor
yang mengimplementasikan versi dengan ukuran. Kita dapat membayangkan suatu hari memiliki 'ExportXMLVisitor` yang menghasilkan data dalam XML, atau pengunjung lain yang menghasilkannya di JSON, dll. Kita bahkan dapat memiliki pengunjung yang menampilkan pohon direktori saya menggunakan bahasa grafis seperti DOT , untuk divisualisasikan dengan program lain.Sebagai catatan terakhir: Kompleksitas Pengunjung dengan pengiriman ganda berarti lebih sulit untuk dipahami, untuk kode dan debug. Singkatnya, ia memiliki faktor geek yang tinggi dan bertentangan dengan prinsip KISS. Dalam survei yang dilakukan oleh para peneliti, Pengunjung terbukti menjadi pola yang kontroversial (tidak ada konsensus tentang kegunaannya). Beberapa percobaan bahkan menunjukkan itu tidak membuat kode lebih mudah dipelihara.
sumber
Menurut pendapat saya, jumlah pekerjaan untuk menambah operasi baru kurang lebih sama dengan menggunakan
Visitor Pattern
atau modifikasi langsung dari masing-masing struktur elemen. Juga, jika saya menambahkan kelas elemen baru, katakanlahCow
, antarmuka Operasi akan terpengaruh dan ini menyebar ke semua kelas elemen yang ada, karena itu membutuhkan kompilasi ulang semua kelas elemen. Jadi apa gunanya?sumber
rootElement.visit (node) -> node.collapse()
. Dengan pengunjung, setiap node mengimplementasikan grafik traversal untuk semua anak-anaknya sehingga Anda selesai.levelsRemaining
penghitung sebagai parameter. Kurangi sebelum memanggil anak-anak tingkat selanjutnya. Di dalam pengunjung Andaif(levelsRemaining == 0) return
.Pola Pengunjung sebagai implementasi bawah tanah yang sama untuk pemrograman Objek Aspect ..
Misalnya jika Anda mendefinisikan operasi baru tanpa mengubah kelas elemen di mana ia beroperasi
sumber
Deskripsi singkat tentang pola pengunjung. Kelas-kelas yang membutuhkan modifikasi semua harus menerapkan metode 'accept'. Klien menyebut metode penerimaan ini untuk melakukan beberapa tindakan baru pada keluarga kelas itu sehingga memperluas fungsionalitasnya. Klien dapat menggunakan metode yang diterima ini untuk melakukan berbagai tindakan baru dengan meneruskan kelas pengunjung yang berbeda untuk setiap tindakan tertentu. Kelas pengunjung berisi beberapa metode kunjungan yang diganti-ganti yang mendefinisikan cara mencapai tindakan spesifik yang sama untuk setiap kelas dalam keluarga. Metode kunjungan ini dilewatkan sebagai contoh untuk bekerja.
Ketika Anda mungkin mempertimbangkan menggunakannya
sumber
Saya tidak mengerti pola ini sampai saya menemukan artikel paman bob dan membaca komentar. Pertimbangkan kode berikut:
Walaupun terlihat bagus karena mengonfirmasi ke Single Responsibility, itu melanggar prinsip Terbuka / Tertutup . Setiap kali Anda memiliki tipe Karyawan baru Anda harus menambahkan jika dengan tipe check. Dan jika Anda tidak mau, Anda tidak akan pernah tahu itu pada waktu kompilasi.
Dengan pola pengunjung, Anda dapat membuat kode Anda lebih bersih karena tidak melanggar prinsip terbuka / tertutup dan tidak melanggar tanggung jawab tunggal. Dan jika Anda lupa menerapkan kunjungan, itu tidak akan dikompilasi:
Keajaibannya adalah walaupun
v.Visit(this)
terlihat sama, kenyataannya berbeda karena memanggil pengunjung yang berlebihan.sumber
Berdasarkan jawaban yang sangat baik dari @Federico A. Ramponi.
Bayangkan saja Anda memiliki hierarki ini:
Apa yang terjadi jika Anda perlu menambahkan metode "Jalan" di sini? Itu akan menyakitkan bagi seluruh desain.
Pada saat yang sama, menambahkan metode "Jalan" menghasilkan pertanyaan baru. Bagaimana dengan "Makan" atau "Tidur"? Haruskah kita benar-benar menambahkan metode baru ke hierarki Hewan untuk setiap tindakan atau operasi baru yang ingin kita tambahkan? Itu jelek dan yang paling penting, kita tidak akan pernah bisa menutup antarmuka Animal. Jadi, dengan pola pengunjung, kita dapat menambahkan metode baru ke hierarki tanpa memodifikasi hierarki!
Jadi, cukup periksa dan jalankan contoh C # ini:
sumber
Dog
sertaCat
. Anda bisa membuatnya di kelas dasar sehingga mereka mewarisi atau memilih contoh yang cocok.Pengunjung
Struktur pengunjung:
Gunakan pola Pengunjung jika:
Meskipun pola Pengunjung memberikan fleksibilitas untuk menambahkan operasi baru tanpa mengubah kode yang ada di Objek, fleksibilitas ini telah datang dengan kelemahan.
Jika objek Visitable baru telah ditambahkan, itu memerlukan perubahan kode di kelas Pengunjung & BetonVisitor . Ada solusi untuk mengatasi masalah ini: Gunakan refleksi, yang akan berdampak pada kinerja.
Cuplikan kode:
Penjelasan:
Visitable
(Element
) adalah antarmuka dan metode antarmuka ini harus ditambahkan ke satu set kelas.Visitor
adalah antarmuka, yang berisi metode untuk melakukan operasi padaVisitable
elemen.GameVisitor
adalah kelas, yang mengimplementasikanVisitor
antarmuka (ConcreteVisitor
).Visitable
elemen menerimaVisitor
dan menjalankan metodeVisitor
antarmuka yang relevan .Game
sebagaiElement
dan permainan beton sepertiChess,Checkers and Ludo
sebagaiConcreteElements
.Dalam contoh di atas,
Chess, Checkers and Ludo
ada tiga permainan yang berbeda (danVisitable
kelas). Pada suatu hari yang cerah, saya menemukan skenario untuk mencatat statistik setiap pertandingan. Jadi tanpa memodifikasi kelas individu untuk mengimplementasikan fungsionalitas statistik, Anda dapat memusatkan tanggung jawab itu diGameVisitor
kelas, yang melakukan trik untuk Anda tanpa mengubah struktur setiap permainan.keluaran:
Mengacu pada
artikel oodesign
sumber pembuatan artikel
untuk lebih jelasnya
Penghias
Pos terkait:
Pola dekorator untuk IO
Kapan Menggunakan Pola Penghias?
sumber
Saya sangat suka deskripsi dan contoh dari http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Visitor.html .
sumber
Sementara saya mengerti bagaimana dan kapan, saya tidak pernah mengerti mengapa. Jika itu membantu siapa saja dengan latar belakang dalam bahasa seperti C ++, Anda ingin membaca ini dengan sangat hati-hati.
Untuk yang malas, kami menggunakan pola pengunjung karena "sementara fungsi virtual dikirim secara dinamis di C ++, fungsi kelebihan beban dilakukan secara statis" .
Atau, dengan kata lain, untuk memastikan bahwa CollideWith (ApolloSpacecraft &) dipanggil saat Anda melewati referensi SpaceShip yang sebenarnya terikat pada objek ApolloSpacecraft.
sumber
Terima kasih atas penjelasan mengagumkan dari @Federico A. Ramponi , saya baru saja membuat ini dalam versi java . Semoga ini bisa membantu.
Juga seperti yang ditunjukkan @Konrad Rudolph , sebenarnya ini adalah pengiriman ganda menggunakan dua contoh konkret bersama untuk menentukan metode run-time.
Jadi sebenarnya tidak perlu membuat antarmuka umum untuk pelaksana operasi selama kita memiliki antarmuka operasi yang ditetapkan dengan benar.
Seperti yang Anda harapkan, antarmuka umum akan membawa kita lebih jelas meskipun sebenarnya bukan bagian penting dalam pola ini.
sumber
pertanyaan Anda adalah kapan harus tahu:
saya tidak pertama kode dengan pola pengunjung. saya kode standar dan menunggu kebutuhan terjadi & kemudian refactor. jadi katakanlah Anda memiliki beberapa sistem pembayaran yang Anda instal satu per satu. Pada waktu checkout Anda dapat memiliki banyak kondisi jika (atau instanceOf), misalnya:
sekarang bayangkan saya punya 10 metode pembayaran, jadi agak jelek. Jadi ketika Anda melihat pola semacam itu yang terjadi pengunjung datang dengan mudah untuk memisahkan semua itu dan Anda akhirnya memanggil sesuatu seperti ini setelahnya:
Anda dapat melihat bagaimana menerapkannya dari sejumlah contoh di sini, saya hanya menunjukkan Anda usecase.
sumber