Mode Pengunjung di Delphi memperluas mode dasar Pengunjung. Untuk informasi lebih lanjut tentang mode Pengunjung, silakan lihat [Gam+, halaman331..344].
Merupakan operasi yang beroperasi pada elemen struktur objek yang dinetralkan. Ini memungkinkan Anda untuk menentukan operasi baru yang bekerja pada setiap elemen tanpa mengubah kelasnya.
[Gam+, halaman331].
Pertimbangkan alat pemodelan berorientasi objek, seperti 'Rational Rose, ModelMaker', yang mewakili model sebagai kelas dan anggota kelas.
Alat pemodelan menyediakan banyak fungsi untuk anggota operasi, seperti: membuat daftar semua anggota kelas, menghasilkan kerangka kode kelas, rekayasa balik, dll.
Sebagian besar operasi ini melakukan operasi berbeda pada anggota yang berbeda. Ini membagi anggota ke dalam bidang, metode,
Properti (PROperti). Oleh karena itu, kita harus membuat kelas yang khusus menangani field, kelas yang khusus menangani metode, dan sebagainya. Pengumpulan kelas anggota tentu saja bergantung pada bahasa yang disusun. Namun tidak banyak perubahan untuk bahasa tertentu.
Gambar tersebut menunjukkan kerangka beberapa kelas anggota. Masalah muncul, jika saya menyebarkan semua operasi ini ke kelas anggota yang berbeda,
Ini akan membuat keseluruhan sistem sulit untuk dipahami, dimodifikasi, dan dipelihara. Menggabungkan pembuatan kode kelas dengan pemeriksaan anggota kelas akan menimbulkan kebingungan. Beberapa kelas perlu dikompilasi ulang ketika menambahkan operasi baru (setidaknya semua sistem terkait harus dikompilasi ulang juga). Ada caranya: Anda bisa menambahkan operasi baru secara independen dari kelas anggota sebagai operasi yang bekerja padanya.
Untuk mencapai dua tujuan di atas, kita dapat menggabungkan operasi yang relevan di setiap kelas dalam objek independen (disebut pengunjung )
Dan meneruskan objek ini ke anggota saat ini ketika melakukan iterasi melalui daftar anggota kelas. Ketika seorang anggota 'menerima' akses, anggota tersebut mengirimkan permintaan yang berisi informasinya sendiri kepada pengunjung. Anggota menganggap dirinya sebagai parameter. Pengunjung melakukan tindakan ini.
Misalnya: pembuat kode yang tidak menggunakan pengunjung dapat menghasilkan kode melalui metode abstrak kelas anggota: TMember.WriteInterfaceCode(Output: TStream). Setiap anggota akan memanggil WriteInterfaceCode untuk menghasilkan kode keluaran yang sesuai. Jika kode dihasilkan melalui pengunjung, objek TinterfaceCodeVisitor akan dibuat dan metode AcceptVisitor dengan parameter sebagai objek akses akan dipanggil di daftar anggota. Setiap anggota yang mengimplementasikan AcceptVisitor akan memanggil kembali pengunjung : sebuah field akan memanggil metode VisitField pengunjung, dan sebuah metode akan memanggil metode VisitMethod. Dengan cara ini, operasi WriteInterfaceCode dari kelas Tfield sebelumnya kini menjadi operasi VisitField dari TinterfaceCodeVisitor.
Untuk membuat pengunjung melakukan lebih dari sekedar pembuatan kode, kita memerlukan semua pengunjung daftar anggota untuk memiliki kelas induk abstrak TmemberVisitor. TmemberVisitor harus menentukan metode untuk setiap anggota. Aplikasi yang perlu mengeluarkan anggota ke format HTML akan menentukan subkelas baru TmemberVisitor dan tidak perlu lagi menambahkan kode khusus aplikasi ke kelas anggota. Pola Pengunjung merangkum setiap operasi dalam Pengunjung terkait
Dengan menggunakan pola Pengunjung, dua level kelas harus ditentukan: satu sesuai dengan elemen yang menerima operasi (tingkat Tmember) dan yang lainnya ditentukan untuk operasi pada elemen (tingkat TmemberVisitor). Saat menambahkan operasi baru, cukup tambahkan subkelas baru ke hierarki pengunjung. Saya mungkin mendefinisikan subkelas TmemberVisitor baru untuk menambahkan fungsionalitas baru.
Kode berikut menunjukkan penerapan pola Pengunjung kelas Tmember yang dijelaskan di atas.
jenis
TMember = kelas (TObject)
publik
prosedur AcceptMemberVisitor(Pengunjung: TMemberVisitor);
akhir;
TField = kelas (TMember)
publik
prosedur AcceptMemberVisitor(Pengunjung: TMemberVisitor override);
akhir;
Metode T = kelas (TAnggota)
publik
prosedur AcceptMemberVisitor(Pengunjung: TMemberVisitor override);
akhir;
TProperti = kelas (TMember)
publik
prosedur AcceptMemberVisitor(Pengunjung: TMemberVisitor override);
akhir;
TMemberVisitor = kelas (TObject)
publik
prosedur VisitField(Contoh: TFfield);
prosedur VisitMember(Contoh: TMember);
prosedur VisitMethod(Contoh: TMethod);
prosedur VisitProperty(Contoh: TProperty);
akhir;
pelaksanaan
{Anggota}
mulai
Pengunjung.VisitMember(Mandiri);
akhir;
{Bidang}
prosedur TField.AcceptMemberVisitor(Pengunjung: TMemberVisitor);
mulai
akhir;
{ Metode }
procedure TMethod.AcceptMemberVisitor(Pengunjung: TMemberVisitor);
mulai
Pengunjung.Metode Kunjungan(Mandiri);
akhir;
{TPProperti}
prosedur TProperty.AcceptMemberVisitor(Pengunjung: TMemberVisitor);
mulai
Pengunjung.VisitProperty(Mandiri);
akhir;
{ Pengunjung Anggota }
prosedur TMemberVisitor.VisitField(Contoh: TField);
mulai
akhir;
prosedur TMemberVisitor.VisitMember(Contoh: TMember);
mulai
akhir;
prosedur TMemberVisitor.VisitMethod(Instance: TMethod);
mulai
akhir;
prosedur TMemberVisitor.VisitProperty(Contoh: TProperty);
mulai
akhir;
menjelaskan:
? TMember, TField, TMethod dan Tproperty semuanya mengimplementasikan metode AcceptMemberVisitor
? Kelas TMemberVisitor mengimplementasikan VisitMember, VisitField dan metode lainnya. TmemberVisitor adalah kelas abstrak, dan semua metodenya diimplementasikan oleh subkelas konkret.
Di bawah ini adalah implementasi generator kode sederhana.
Pengenalan kode:
• TCodeGenerationVisitor adalah pengunjung untuk pembuat kode yang mengimplementasikan anggota.
? Pengunjung mendefinisikan properti peka konteks: Output: TTextStream,
? Ini harus disetel sebelum VisitXXX dipanggil. Misalnya: DrawingVisitor biasanya memerlukan konteks termasuk kanvas untuk mendukung operasi menggambar. Konteksnya ditetapkan ke pembuat kode sebelum melakukan iterasi melalui seluruh pasangan anggota.
? Pembuat kode akan menggabungkan semua kode untuk kelas yang dihasilkan
Untuk benar-benar memahami mode Pengunjung, Anda dapat menjalankan contoh ini dan mempelajari lebih lanjut mekanisme pengiriman ganda: terima/kunjungi.
unit CodeGenerator;
antarmuka
menggunakan Kelas, TextStreams;
jenis
TCodeGenerator = kelas (TObject)
publik
prosedur Hasilkan(Anggota: TList; Keluaran: TTextStream);
akhir;
pelaksanaan
menggunakan Anggota;
jenis
TCodeGenerationVisitor = kelas (TMemberVisitor)
pribadi
Keluaran: TTextStream;
publik
prosedur VisitField(Contoh: TField);
prosedur VisitMethod(Contoh: TMetode);
prosedur VisitProperty(Contoh: TProperty);
properti Output: TTextStream baca FOutput tulis FOutput;
akhir;
{TCodeGenerationVisitor}
prosedur TCodeGenerationVisitor.VisitField(Contoh: TField);
mulai
Output.WriteLnFmt(' %s: %s;', [Nama.Instance, NamaData Instance]);
akhir;
prosedur TCodeGenerationVisitor.VisitMethod(Contoh: TMethod);
var
MKStr, DTStr: tali;
mulai
case Instance.MethodJenis
mkConstructor: MKStr := 'konstruktor';
mkDestructor: MKStr := 'penghancur';
mkProsedur: MKStr := 'prosedur';
mkFuntion: MKStr := 'fungsi';
akhir;
jika Instance.MethodKind = mkFunction maka
DTStr := ': ' + Instance.DataName
kalau tidak
DTStr := ';
{Kode tidak lengkap, cukup untuk mendemonstrasikan pembuatan kode metode}
Keluaran.WriteLnFmt(' %s %s%s%s;'
[MKStr, Instance.Name, Instance.Parameter, DTStr]);
akhir;
prosedur TCodeGenerationVisitor.VisitProperty(Contoh: TProperty);
mulai
Output.WriteLnFmt(' properti %s: %s baca %s tulis %s;',
[Instance.Nama, Instance.DataName,
Instance.ReadSpecifier, Instance.WriteSpecifier]);
akhir;
{TCodeGenerator}
procedure TCodeGenerator.Generate(Anggota: TList; Output: TTextStream);
var
Saya: Bilangan Bulat;
mulai
{Tulis definisi kelas}
Output.WriteLine('TSample = kelas (TObject)');
{Bagus! Pengunjung yang bergabung dengan pembuat kode}
Pengunjung := TCodeGenerationVisitor.Buat;
Mencoba
{Ingatlah untuk memberikan konteks bagi semua kunjungan untuk akses yang lebih baik ke metode VisitXXX. }
untuk I := 0 hingga Anggota.Hitungan - 1 lakukan
{Bagian kode spesifik tempat sesuatu yang baik terjadi}
TMember(Anggota[I]).AcceptMemberVisitor(Pengunjung);
Akhirnya
Pengunjung.Gratis;
akhir;
{Pembuatan kode untuk anggota kelas selesai}
Output.WriteLine('akhir;');
akhir;
Pengorganisasian
//Banyak kutipan dari "Pola Desain",