Pola Desain Pengunjung di Jawa

1. Ikhtisar

Dalam tutorial ini, kami akan memperkenalkan salah satu pola desain GoF perilaku - Pengunjung.

Pertama, kami akan menjelaskan tujuannya dan masalah yang coba dipecahkannya.

Selanjutnya, kita akan melihat diagram UML Pengunjung dan penerapan contoh praktisnya.

2. Pola Desain Pengunjung

Tujuan pola Pengunjung adalah untuk menentukan operasi baru tanpa memperkenalkan modifikasi pada struktur objek yang ada.

Bayangkan kita memiliki kompositobjek yang terdiri dari komponen. Struktur objek sudah diperbaiki - kita tidak dapat mengubahnya, atau kita tidak berencana untuk menambahkan jenis elemen baru ke struktur.

Sekarang, bagaimana kita bisa menambahkan fungsionalitas baru ke kode kita tanpa modifikasi kelas yang ada?

Pola desain Pengunjung mungkin bisa menjadi jawabannya. Sederhananya, yang harus kita lakukan adalah menambahkan fungsi yang menerima kelas pengunjung ke setiap elemen struktur.

Dengan begitu, komponen kami akan memungkinkan implementasi pengunjung untuk "mengunjungi" mereka dan melakukan tindakan yang diperlukan pada elemen itu.

Dengan kata lain, kita akan mengekstrak algoritma yang akan diterapkan pada struktur objek dari kelas.

Akibatnya, kami akan memanfaatkan prinsip Buka / Tertutup dengan baik karena kami tidak akan mengubah kode, tetapi kami masih dapat memperluas fungsionalitas dengan menyediakan penerapan Pengunjung baru .

3. Diagram UML

Pada diagram UML di atas, kami memiliki dua hierarki implementasi, pengunjung khusus, dan elemen konkret.

Pertama-tama, klien menggunakan implementasi Pengunjung dan menerapkannya ke struktur objek. Objek gabungan mengulangi komponennya dan menerapkan pengunjung ke masing-masing komponen.

Sekarang, yang paling relevan adalah elemen beton (ConcreteElementA dan ConcreteElementB) menerima Pengunjung, hanya mengizinkannya untuk mengunjunginya .

Terakhir, metode ini sama untuk semua elemen dalam struktur, metode ini melakukan pengiriman ganda dengan meneruskan dirinya (melalui kata kunci ini ) ke metode kunjungan pengunjung.

4. Implementasi

Contoh kami adalah objek Dokumen kustom yang terdiri dari elemen beton JSON dan XML; elemen memiliki superclass abstrak umum, Element.

Kelas Dokumen :

public class Document extends Element { List elements = new ArrayList(); // ... @Override public void accept(Visitor v) { for (Element e : this.elements) { e.accept(v); } } }

Kelas Elemen memiliki metode abstrak yang menerima antarmuka Pengunjung :

public abstract void accept(Visitor v);

Oleh karena itu, saat membuat elemen baru, beri nama JsonElement , kita harus menyediakan implementasi metode ini.

Namun, karena sifat dari pola Pengunjung, penerapannya akan sama, jadi dalam banyak kasus, kami harus menyalin-tempel kode boilerplate dari elemen lain yang sudah ada:

public class JsonElement extends Element { // ... public void accept(Visitor v) { v.visit(this); } }

Karena elemen kami memungkinkan untuk dikunjungi oleh pengunjung mana pun, katakanlah kami ingin memproses elemen Dokumen kami , tetapi masing-masing elemen tersebut dengan cara yang berbeda, tergantung pada jenis kelasnya.

Oleh karena itu, pengunjung kami akan memiliki metode terpisah untuk jenis yang diberikan:

public class ElementVisitor implements Visitor { @Override public void visit(XmlElement xe) { System.out.println( "processing an XML element with uuid: " + xe.uuid); } @Override public void visit(JsonElement je) { System.out.println( "processing a JSON element with uuid: " + je.uuid); } }

Di sini, pengunjung konkret kami menerapkan dua metode, yang sesuai satu per setiap jenis Elemen .

Ini memberi kita akses ke objek tertentu dari struktur tempat kita dapat melakukan tindakan yang diperlukan.

5. Pengujian

Untuk tujuan pengujian, mari kita lihat kelas VisitorDemo :

public class VisitorDemo { public static void main(String[] args) { Visitor v = new ElementVisitor(); Document d = new Document(generateUuid()); d.elements.add(new JsonElement(generateUuid())); d.elements.add(new JsonElement(generateUuid())); d.elements.add(new XmlElement(generateUuid())); d.accept(v); } // ... }

Pertama, kami membuat Pengunjung Elemen , ini memegang algoritma yang akan kami terapkan ke elemen kami.

Selanjutnya, kami menyiapkan Dokumen kami dengan komponen yang tepat dan menerapkan pengunjung yang akan diterima oleh setiap elemen struktur objek.

Outputnya akan seperti ini:

processing a JSON element with uuid: fdbc75d0-5067-49df-9567-239f38f01b04 processing a JSON element with uuid: 81e6c856-ddaf-43d5-aec5-8ef977d3745e processing an XML element with uuid: 091bfcb8-2c68-491a-9308-4ada2687e203

Ini menunjukkan bahwa pengunjung telah mengunjungi setiap elemen dari struktur kami, tergantung pada jenis Elemen , ia mengirimkan pemrosesan ke metode yang sesuai dan dapat mengambil data dari setiap objek yang mendasarinya.

6. Kerugian

Karena setiap pola desain, bahkan Pengunjung memiliki kelemahannya sendiri, khususnya, penggunaannya membuat lebih sulit untuk memelihara kode jika kita perlu menambahkan elemen baru ke struktur objek.

Misalnya, jika kita menambahkan YamlElement baru , maka kita perlu memperbarui semua pengunjung yang ada dengan metode baru yang diinginkan untuk memproses elemen ini. Selanjutnya, jika kita memiliki sepuluh atau lebih pengunjung konkret, mungkin merepotkan untuk memperbarui semuanya.

Selain itu, saat menggunakan pola ini, logika bisnis yang terkait dengan satu objek tertentu tersebar di semua implementasi pengunjung.

7. Kesimpulan

Pola Pengunjung sangat bagus untuk memisahkan algoritme dari kelas tempatnya beroperasi. Selain itu, menambah operasi baru menjadi lebih mudah, hanya dengan menyediakan implementasi baru dari Pengunjung.

Selain itu, kami tidak bergantung pada antarmuka komponen, dan jika berbeda, tidak masalah, karena kami memiliki algoritme terpisah untuk pemrosesan per elemen beton.

Selain itu, Pengunjung pada akhirnya dapat menggabungkan data berdasarkan elemen yang dilintasi.

Untuk melihat versi yang lebih khusus dari pola desain Pengunjung, lihat pola pengunjung di Java NIO - penggunaan pola di JDK.

Seperti biasa, kode lengkap tersedia di proyek Github.