Konteks
Saya telah menggunakan dengan hierarki objek (pohon ekspresi) pola pengunjung "semu" (semu, karena di dalamnya tidak menggunakan pengiriman ganda):
public interface MyInterface
{
void Accept(SomeClass operationClass);
}
public class MyImpl : MyInterface
{
public void Accept(SomeClass operationClass)
{
operationClass.DoSomething();
operationClass.DoSomethingElse();
// ... and so on ...
}
}
Desain ini, bagaimanapun dapat dipertanyakan, cukup nyaman karena jumlah implementasi MyInterface signifikan (~ 50 atau lebih) dan saya tidak perlu menambahkan operasi tambahan.
Setiap implementasi unik (ini ekspresi atau operator yang berbeda), dan beberapa komposit (yaitu, simpul operator yang akan berisi simpul operator / daun lainnya).
Traversal saat ini dilakukan dengan memanggil operasi Terima pada simpul akar pohon, yang pada gilirannya memanggil Terima pada masing-masing simpul anaknya, yang pada gilirannya ... dan seterusnya ...
Tetapi saatnya telah tiba di mana saya perlu menambahkan operasi baru , seperti pencetakan cantik:
public class MyImpl : MyInterface
{
// Property does not come from MyInterface
public string SomeProperty { get; set; }
public void Accept(SomeClass operationClass)
{
operationClass.DoSomething();
operationClass.DoSomethingElse();
// ... and so on ...
}
public void Accept(SomePrettyPrinter printer)
{
printer.PrettyPrint(this.SomeProperty);
}
}
Saya pada dasarnya melihat dua opsi:
- Jaga desain yang sama, menambahkan metode baru untuk operasi saya ke setiap kelas turunan, dengan biaya pemeliharaan (bukan pilihan, IMHO)
- Gunakan pola Pengunjung "benar", dengan biaya ekstensibilitas (bukan opsi, karena saya perkirakan akan ada lebih banyak implementasi yang datang di sepanjang jalan ...), dengan sekitar 50+ kelebihan metode Kunjungan, masing-masing cocok dengan implementasi tertentu ?
Pertanyaan
Apakah Anda akan merekomendasikan menggunakan pola Pengunjung? Apakah ada pola lain yang bisa membantu menyelesaikan masalah ini?
MyInterface
.. apakah semua kelas memiliki implementasi unikDoSomething
danDoSomethingElse
? Saya tidak melihat di mana kelas pengunjung Anda benar-benar melintasi hierarki - sepertinya lebih sepertifacade
saat ini ..Jawaban:
Saya telah menggunakan pola pengunjung untuk mewakili pohon ekspresi selama 10+ tahun pada enam proyek skala besar dalam tiga bahasa pemrograman, dan saya sangat senang dengan hasilnya. Saya menemukan beberapa hal yang membuat penerapan pola jauh lebih mudah:
Jangan gunakan kelebihan beban di antarmuka pengunjung
Masukkan tipe ke dalam nama metode, yaitu digunakan
daripada
Tambahkan metode "tangkap tidak dikenal" ke antarmuka pengunjung Anda.
Itu akan memungkinkan bagi pengguna yang tidak dapat mengubah kode Anda:
Ini akan membuat mereka membangun implementasi mereka sendiri
IExpression
danIVisitor
yang "memahami" ekspresi mereka dengan menggunakan informasi tipe run-time dalam implementasiVisitExpression
metode catch-all mereka .Menyediakan implementasi
IVisitor
antarmuka tanpa-apa-apa yang bakuIni akan memungkinkan pengguna yang perlu berurusan dengan subset jenis ekspresi membangun pengunjung mereka lebih cepat, dan membuat kode mereka kebal terhadap Anda menambahkan lebih banyak metode
IVisitor
. Misalnya, menulis pengunjung yang memanen semua nama variabel dari ekspresi Anda menjadi tugas yang mudah, dan kode tidak akan pecah bahkan jika Anda menambahkan banyak jenis ekspresi baru ke AndaIVisitor
nanti.sumber
Do not use overloads in the interface of the visitor
?