Katakanlah saya memiliki pembuat ujian, sehingga guru dapat membuat banyak pertanyaan untuk ujian.
Namun, tidak semua pertanyaan sama: Anda memiliki banyak pilihan, kotak teks, pencocokan, dan sebagainya. Setiap jenis pertanyaan ini perlu menyimpan berbagai jenis data, dan memerlukan GUI yang berbeda untuk pencipta dan untuk peserta tes.
Saya ingin menghindari dua hal:
- Ketik cek atau ketik casting
- Apa pun yang terkait dengan GUI dalam kode data saya.
Dalam upaya awal saya, saya berakhir dengan kelas-kelas berikut:
class Test{
List<Question> questions;
}
interface Question { }
class MultipleChoice implements Question {}
class TextBox implements Question {}
Namun, ketika saya pergi untuk menampilkan tes, saya pasti akan berakhir dengan kode seperti:
for (Question question: questions){
if (question instanceof MultipleChoice){
display.add(new MultipleChoiceViewer());
}
//etc
}
Ini terasa seperti masalah yang sangat umum. Apakah ada pola desain yang memungkinkan saya memiliki pertanyaan polimorfik sambil menghindari item yang tercantum di atas? Atau apakah polimorfisme ide yang salah sejak awal?
design-patterns
polymorphism
Nathan Merrill
sumber
sumber
Jawaban:
Anda dapat menggunakan pola pengunjung:
Pilihan lain adalah serikat terdiskriminasi. Ini akan sangat tergantung pada bahasa Anda. Ini jauh lebih baik jika bahasa Anda mendukungnya, tetapi banyak bahasa populer tidak.
sumber
visit
(kunjungan pengunjung). Juga metode dalam objek yang dikunjungi biasanya disebutaccept(Visitor)
(objek menerima pengunjung). Lihat oodesign.com/visitor-pattern.htmlDalam C # / WPF (dan, saya bayangkan, dalam bahasa desain yang berfokus pada UI lainnya), kami memiliki DataTemplates . Dengan mendefinisikan templat data, Anda membuat hubungan antara satu jenis "objek data" dan "templat UI" khusus yang dibuat khusus untuk menampilkan objek itu.
Setelah Anda memberikan instruksi kepada UI untuk memuat objek jenis tertentu, ia akan melihat apakah ada templat data yang ditentukan untuk objek tersebut.
sumber
Jika setiap jawaban dapat dikodekan sebagai string, Anda dapat melakukan ini:
Di mana string kosong menandakan sebuah pertanyaan tanpa jawaban untuk itu. Ini memungkinkan pertanyaan, jawaban, dan GUI untuk dipisahkan namun memungkinkan untuk polimorfisme.
Kotak teks, pencocokan, dan sebagainya dapat memiliki desain yang serupa, semua mengimplementasikan antarmuka pertanyaan. Konstruksi string jawaban terjadi dalam tampilan. String jawaban mewakili kondisi pengujian. Mereka harus disimpan ketika siswa berkembang. Menerapkannya pada pertanyaan memungkinkan menampilkan tes dan statusnya dalam cara yang bertingkat dan tidak bertingkat.
Dengan memisahkan output menjadi
display()
dandisplayGraded()
tampilan tidak perlu ditukar dan tidak perlu dilakukan percabangan pada parameter. Namun, setiap tampilan bebas untuk menggunakan kembali logika tampilan sebanyak mungkin saat menampilkan. Skema apa pun yang dirancang untuk melakukan itu tidak perlu bocor ke dalam kode ini.Namun, jika Anda ingin memiliki kontrol yang lebih dinamis tentang bagaimana sebuah pertanyaan ditampilkan, Anda dapat melakukan ini:
dan ini
Ini memang memiliki kekurangan yang membutuhkan tampilan yang tidak bermaksud untuk menampilkan
score()
atauanswerKey
bergantung pada mereka ketika mereka tidak membutuhkannya. Tetapi itu berarti Anda tidak perlu membangun kembali pertanyaan tes untuk setiap jenis tampilan yang ingin Anda gunakan.sumber
Menurut pendapat saya, jika Anda membutuhkan fitur generik seperti itu, saya akan mengurangi kopling antara hal-hal dalam kode. Saya akan mencoba mendefinisikan jenis Pertanyaan yang lebih umum yang saya bisa, dan setelah itu saya akan membuat kelas yang berbeda untuk objek penyaji. Silakan lihat contoh di bawah ini:
Kemudian, untuk bagian rendering, saya menghapus pemeriksaan Tipe dengan menerapkan pemeriksaan sederhana pada data dalam objek pertanyaan. Kode di bawah ini mencoba menyelesaikan dua hal: (i) hindari pengecekan tipe dan hindari pelanggaran prinsip "L" (substitusi Liskov dalam SOLID) dengan menghapus subtipe kelas Pertanyaan; dan (ii) membuat kode dapat diperluas, dengan tidak pernah mengubah kode rendering inti di bawah ini, hanya menambahkan lebih banyak implementasi QuestionView dan instansnya ke array (ini sebenarnya prinsip "O" dalam SOLID - buka untuk ekstensi dan ditutup untuk modifikasi).
sumber
Sebuah pabrik harus dapat melakukan ini. Peta menggantikan pernyataan sakelar, yang diperlukan hanya untuk memasangkan Pertanyaan (yang tidak tahu apa-apa tentang tampilan) dengan QuestionView.
Dengan ini tampilan menggunakan jenis Pertanyaan spesifik yang dapat ditampilkan, dan model tetap terputus dari tampilan.
Pabrik dapat diisi melalui refleksi atau secara manual saat aplikasi dimulai.
sumber
Question
memasukkan ke dalamMultipleChoiceQuestion
ketika Anda membuatMultipleChoiceView
Saya tidak yakin ini dianggap sebagai "menghindari pemeriksaan tipe", tergantung pada bagaimana perasaan Anda tentang refleksi .
sumber
if
tipe ke pemeriksaandictionary
tipe. Seperti bagaimana Python menggunakan kamus alih-alih beralih pernyataan. Yang mengatakan, saya suka cara ini lebih dari daftar pernyataan if.template <typename Q> struct question_traits;
dengan spesialisasi yang sesuai