Misalkan saya memiliki objek khusus, Siswa :
public class Student{
public int _id;
public String name;
public int age;
public float score;
}
Dan kelas, Window , yang digunakan untuk menampilkan informasi seorang Siswa :
public class Window{
public void showInfo(Student student);
}
Kelihatannya cukup normal, tetapi saya mendapati Window tidak cukup mudah untuk diuji secara individual, karena dibutuhkan objek Student yang sebenarnya untuk memanggil fungsi tersebut. Jadi saya mencoba untuk memodifikasi showInfo sehingga tidak menerima objek Siswa secara langsung:
public void showInfo(int _id, String name, int age, float score);
sehingga lebih mudah untuk menguji Window secara individual:
showInfo(123, "abc", 45, 6.7);
Tetapi saya menemukan versi yang dimodifikasi memiliki masalah lain:
Ubah Siswa (misalnya: tambahkan properti baru) memerlukan modifikasi metode-tanda tangan showInfo
Jika Siswa memiliki banyak properti, metode-tanda tangan Siswa akan sangat panjang.
Jadi, menggunakan objek khusus sebagai parameter atau menerima setiap properti dalam objek sebagai parameter, mana yang lebih bisa dipertahankan?
showInfo
membutuhkan String nyata, float nyata dan dua int nyata. Bagaimana menyediakanString
objek nyata lebih baik daripada menyediakanStudent
objek nyata ?int
parameter. Dari situs panggilan, tidak ada verifikasi bahwa Anda benar-benar melewati mereka dalam urutan yang benar. Bagaimana jika Anda bertukarid
danage
, ataufirstName
danlastName
? Anda memperkenalkan titik kegagalan potensial yang bisa sangat sulit dideteksi hingga meledak di wajah Anda, dan Anda menambahkannya di setiap situs panggilan .showForm(bool, bool, bool, bool, int)
metode lama - Saya suka itu ...Jawaban:
Menggunakan objek khusus untuk mengelompokkan parameter terkait sebenarnya merupakan pola yang disarankan. Sebagai refactoring, itu disebut Pengantar Parameter Objek .
Masalahmu ada di tempat lain. Pertama, generik
Window
seharusnya tidak tahu apa-apa tentang Siswa. Sebagai gantinya, Anda harus memiliki beberapa jenisStudentWindow
yang tahu tentang hanya menampilkanStudents
. Kedua, sama sekali tidak ada masalah tentang membuatStudent
instance untuk diujiStudentWindow
selamaStudent
tidak mengandung logika kompleks yang secara drastis akan mempersulit pengujianStudentWindow
. Jika memang memiliki logika itu maka membuatStudent
antarmuka dan mengejek itu harus lebih disukai.sumber
Student
pengelompokan akal dan kemungkinan akan muncul di daerah lain dari aplikasi.Student
, Itu akan menjadi Preserve Whole Objecta.b.c
jika metode Anda mengambila
. Jika metode Anda sampai pada titik di mana Anda perlu memiliki lebih dari 4 parameter atau 2 level dalam aksesi properti, mungkin perlu diperhitungkan. Perhatikan juga bahwa ini adalah pedoman - seperti semua pedoman lainnya, pedoman ini memerlukan kebijaksanaan pengguna. Jangan mengikutinya secara membabi buta.Anda mengatakan itu
Tetapi Anda bisa membuat objek siswa untuk diteruskan ke jendela Anda:
Tampaknya tidak terlalu rumit untuk dihubungi.
sumber
Student
merujuk ke aUniversity
, yang mengacu pada banyakFaculty
s danCampus
s, denganProfessor
s danBuilding
s, tidak ada yangshowInfo
benar-benar menggunakan, tetapi Anda belum mendefinisikan antarmuka apa pun yang memungkinkan tes untuk "mengetahui" itu dan hanya memasok siswa yang relevan data, tanpa membangun seluruh organisasi. ContohnyaStudent
adalah objek data biasa dan, seperti yang Anda katakan, pengujian harus dilakukan dengan senang hati.Dalam istilah awam:
Sunting:
Sebagai @ Tom.Bowen89 menyatakan tidak jauh lebih kompleks untuk menguji metode showinfo:
sumber
sumber
Steve McConnell dalam Code Complete membahas masalah ini, mendiskusikan manfaat dan kelemahan dari melewatkan objek ke dalam metode alih-alih menggunakan properti.
Maafkan saya jika saya salah memahami detailnya, saya bekerja karena ingatan sudah lebih dari setahun sejak saya memiliki akses ke buku:
Dia sampai pada kesimpulan bahwa Anda lebih baik tidak menggunakan objek, alih-alih hanya mengirim properti yang benar-benar diperlukan untuk metode ini. Metode ini seharusnya tidak perlu tahu apa pun tentang objek di luar properti yang akan digunakan sebagai bagian dari operasinya. Selain itu, seiring waktu, jika objek berubah, ini bisa memiliki konsekuensi yang tidak diinginkan pada metode menggunakan objek.
Dia juga mengatakan bahwa jika Anda berakhir dengan metode yang menerima banyak argumen yang berbeda, maka itu mungkin merupakan pertanda bahwa metode tersebut melakukan terlalu banyak dan harus dipecah menjadi lebih banyak, metode yang lebih kecil.
Namun, terkadang, kadang-kadang, Anda benar-benar membutuhkan banyak parameter. Contoh yang dia berikan akan berupa metode yang membangun alamat lengkap, menggunakan banyak properti alamat yang berbeda (meskipun ini bisa didapat dengan menggunakan array string ketika Anda memikirkannya).
sumber
Student
dalam hal ini). Dan inilah cara pengujian menginformasikan desain , sepenuhnya merangkul jawaban terbanyak suara sambil mempertahankan integritas desain.Jauh lebih mudah untuk menulis dan membaca tes jika Anda lulus seluruh objek:
Untuk perbandingan,
baris dapat ditulis, jika Anda memberikan nilai secara terpisah, seperti:
dimana panggilan metode aktual dikuburkan di suatu tempat seperti
Untuk menjadi to the point, bahwa Anda tidak dapat memasukkan panggilan metode yang sebenarnya dalam tes adalah tanda bahwa API Anda buruk.
sumber
Anda harus melewati apa yang masuk akal, beberapa ide:
Lebih mudah untuk diuji. Jika objek perlu diedit, apa yang paling membutuhkan refactoring? Apakah menggunakan kembali fungsi ini untuk tujuan lain bermanfaat? Berapa jumlah paling sedikit informasi yang saya butuhkan untuk memberikan fungsi ini untuk melakukan tujuannya? (Dengan memecahnya - itu memungkinkan Anda menggunakan kembali kode ini - waspada jatuh ke lubang desain pembuatan fungsi ini dan kemudian bottlenecking semuanya untuk secara eksklusif menggunakan objek ini.)
Semua aturan pemrograman ini hanyalah panduan untuk membuat Anda berpikir ke arah yang benar. Hanya saja, jangan membangun binatang kode - jika Anda tidak yakin dan hanya perlu melanjutkan, pilih arah / Anda sendiri atau saran di sini, dan jika Anda mencapai titik di mana Anda berpikir 'oh, saya harus membuat ini cara '- Anda mungkin dapat kembali dan refactor dengan mudah. (Misalnya jika Anda memiliki kelas Guru - hanya perlu properti yang sama ditetapkan sebagai Siswa, dan Anda mengubah fungsi Anda untuk menerima objek apa pun dari formulir Orang)
Saya akan paling cenderung untuk menjaga objek utama yang lewat - karena bagaimana saya kode itu akan lebih mudah menjelaskan apa fungsi ini lakukan.
sumber
Salah satu rute yang umum di sekitar ini adalah memasukkan antarmuka antara dua proses.
Terkadang hal ini sedikit berantakan tetapi beberapa hal menjadi sedikit lebih rapi di Jawa jika Anda menggunakan kelas dalam.
Anda kemudian dapat menguji
Window
kelas dengan hanya memberikannyaHasInfo
objek palsu .Saya menduga ini adalah contoh Pola Penghias .
Ditambahkan
Tampaknya ada beberapa kebingungan yang disebabkan oleh kesederhanaan kode. Berikut ini contoh lain yang dapat menunjukkan teknik yang lebih baik.
sumber
Student
dan diString
sini untuk tipe pengembalian murni untuk demonstrasi. Kemungkinan akan ada parameter tambahan untukgetInfo
sepertiPane
untuk menggambar jika menggambar. Konsep di sini adalah untuk melewatkan komponen fungsional sebagai dekorator dari objek asli .HasInfo
objek.Student
tahu bagaimana menjadi satu.getInfo
mengembalikan batal lulusPane
untuk menggambar, maka implementasi (diStudent
kelas) tiba-tiba digabungkan ke ayunan atau apa pun yang Anda gunakan. Jika Anda membuatnya mengembalikan beberapa string dan mengambil 0 parameter, maka UI Anda tidak akan tahu apa yang harus dilakukan dengan string tanpa asumsi ajaib dan kopling implisit. Jika AndagetInfo
benar - benar mengembalikan beberapa model tampilan dengan properti yang relevan, makaStudent
kelas Anda digabungkan lagi dengan logika presentasi. Saya tidak berpikir salah satu dari alternatif ini diinginkanAnda sudah memiliki banyak jawaban bagus, tetapi berikut adalah beberapa saran yang memungkinkan Anda melihat solusi alternatif:
Contoh Anda menunjukkan Siswa (jelas objek model) diteruskan ke Window (tampaknya objek tingkat tampilan). Pengontrol perantara atau objek Presenter mungkin bermanfaat jika Anda belum memilikinya, memungkinkan Anda mengisolasi antarmuka pengguna dari model Anda. Pengontrol / penyaji harus menyediakan antarmuka yang dapat digunakan untuk menggantinya untuk pengujian UI, dan harus menggunakan antarmuka untuk merujuk ke objek model dan melihat objek agar dapat mengisolasinya dari keduanya untuk pengujian. Anda mungkin perlu memberikan beberapa cara abstrak untuk membuat atau memuat ini (misalnya objek Pabrik, objek Repositori, atau yang serupa).
Mentransfer bagian yang relevan dari objek model Anda ke Obyek Transfer Data adalah pendekatan yang berguna untuk berinteraksi ketika model Anda menjadi terlalu kompleks.
Mungkin Siswa Anda melanggar Prinsip Segregasi Antarmuka. Jika demikian, bisa bermanfaat untuk membaginya menjadi beberapa antarmuka yang lebih mudah untuk dikerjakan.
Pemuatan Malas dapat membuat konstruksi grafik objek besar lebih mudah.
sumber
Ini sebenarnya pertanyaan yang layak. Masalah sebenarnya di sini adalah penggunaan istilah generik "objek", yang bisa sedikit ambigu.
Secara umum, dalam bahasa OOP klasik, istilah "objek" telah berarti "contoh kelas". Contoh kelas bisa sangat berat - properti publik dan pribadi (dan yang di antaranya), metode, pewarisan, dependensi, dll. Anda tidak akan benar-benar ingin menggunakan sesuatu seperti itu untuk sekadar memasukkan beberapa properti.
Dalam hal ini, Anda menggunakan objek sebagai wadah yang hanya menyimpan beberapa primitif. Dalam C ++, objek seperti ini dikenal sebagai
structs
(dan mereka masih ada dalam bahasa seperti C #). Structs, pada kenyataannya, dirancang persis untuk penggunaan yang Anda bicarakan - mereka mengelompokkan objek terkait dan primitif bersama ketika mereka memiliki hubungan logis.Namun, dalam bahasa modern, benar-benar tidak ada perbedaan antara struct dan kelas ketika Anda menulis kode , jadi Anda boleh menggunakan objek. (Namun di belakang layar, ada beberapa perbedaan yang harus Anda perhatikan - misalnya, struct adalah tipe nilai, bukan tipe referensi.) Pada dasarnya, selama Anda menjaga objek Anda sederhana, itu akan mudah untuk menguji secara manual. Bahasa dan alat-alat modern memungkinkan Anda untuk mengurangi ini sedikit, (melalui antarmuka, kerangka kerja mengejek, injeksi ketergantungan, dll.)
sumber
Student
) ke dalam model tampilan (StudentInfo
atauStudentInfoViewModel
dll.), Tetapi mungkin tidak perlu.