Saya bertanya-tanya tentang desain kelas berorientasi objek yang baik. Secara khusus, saya kesulitan menentukan antara opsi-opsi ini:
- metode statis vs contoh
- metode tanpa parameter atau nilai balik vs metode dengan parameter dan nilai balik
- tumpang tindih vs fungsionalitas metode yang berbeda
- metode pribadi vs publik
Contoh 1:
Implementasi ini menggunakan metode instan, tanpa nilai balik atau parameter, tanpa fungsionalitas yang tumpang tindih, dan semua metode publik
XmlReader reader = new XmlReader(url);
reader.openUrl();
reader.readXml();
Document result = reader.getDocument();
Contoh 2:
Implementasi ini menggunakan metode statis, dengan nilai dan parameter pengembalian, dengan fungsionalitas yang tumpang tindih dan metode pribadi
Document result = XmlReader.readXml(url);
Dalam contoh satu, semua metode adalah contoh publik, yang membuatnya mudah untuk unit test. Meskipun semua metode berbeda, readXml () bergantung pada openUrl () di openUrl itu () harus dipanggil terlebih dahulu. Semua data dideklarasikan dalam bidang contoh, jadi tidak ada nilai balik atau parameter dalam metode apa pun, kecuali di konstruktor dan pengakses.
Dalam contoh dua, hanya satu metode yang bersifat publik, sisanya adalah statis privat, yang membuatnya sulit untuk diuji unit. Metode tumpang tindih dalam readXml () yang memanggil openUrl (). Tidak ada bidang, semua data dilewatkan sebagai parameter dalam metode dan hasilnya dikembalikan segera.
Prinsip apa yang harus saya ikuti untuk melakukan pemrograman berorientasi objek yang tepat?
sumber
Jawaban:
Contoh 2 cukup buruk untuk pengujian ... dan saya tidak bermaksud bahwa Anda tidak dapat menguji internal. Anda juga tidak dapat mengganti
XmlReader
objek Anda dengan objek tiruan karena Anda tidak memiliki objek sama sekali.Contoh 1 sulit untuk digunakan. Bagaimana dengan
yang tidak lebih sulit untuk digunakan daripada metode statis Anda.
Hal-hal seperti membuka URL, membaca XML, mengonversi byte ke string, parsing, soket penutup, dan apa pun, tidak menarik. Membuat objek dan menggunakannya adalah penting.
Jadi IMHO, Desain OO yang tepat adalah untuk membuat hanya dua hal yang bersifat publik (kecuali jika Anda benar-benar membutuhkan langkah-langkah perantara untuk beberapa alasan). Statis itu jahat.
sumber
Document result = new XmlReader(url).getDocument();
Mengapa? Sehingga saya dapat memutakhirkannyaDocument result = whateverReader.getDocument();
dan telahwhateverReader
menyerahkannya kepada saya dengan sesuatu yang lain.Inilah masalahnya - tidak ada jawaban yang benar, dan tidak ada definisi absolut dari "desain berorientasi objek yang tepat" (beberapa orang akan menawarkan Anda satu, tetapi mereka naif ... beri mereka waktu).
Semuanya bermuara pada TUJUAN Anda.
Anda seorang seniman, dan kertasnya kosong. Anda dapat menggambar potret sisi hitam dan putih yang halus, dengan pensil halus, atau lukisan abstrak dengan luka besar campuran neon. Atau apa pun di antaranya.
Jadi, apa yang benar untuk masalah yang Anda selesaikan? Apa keluhan orang-orang yang perlu menggunakan kelas Anda untuk bekerja dengan xml? Apa yang sulit dari pekerjaan mereka? Kode apa yang mereka coba tulis yang mengelilingi panggilan ke perpustakaan Anda, dan bagaimana Anda bisa membantu agar mengalir lebih baik untuk mereka?
Apakah mereka mau lebih ringkas? Apakah mereka ingin menjadi sangat pintar dalam mencari tahu nilai default untuk parameter, sehingga mereka tidak perlu menentukan banyak (atau apa pun) dan itu menebak dengan benar? Bisakah Anda mengotomatiskan tugas pengaturan dan pembersihan yang dibutuhkan perpustakaan Anda sehingga mustahil bagi mereka untuk melupakan langkah-langkah itu? Apa lagi yang bisa Anda lakukan untuk mereka?
Sial, yang mungkin perlu Anda lakukan adalah mengkodekannya dengan 4 atau 5 cara berbeda, lalu mengenakan topi konsumen Anda dan menulis kode yang menggunakan semua 5, dan melihat mana yang terasa lebih baik. Jika Anda tidak bisa melakukan itu untuk seluruh pustaka Anda, maka lakukan untuk subset. Dan Anda perlu menambahkan beberapa alternatif tambahan ke daftar Anda juga - bagaimana dengan antarmuka yang lancar, atau pendekatan yang lebih fungsional, atau parameter bernama, atau sesuatu yang didasarkan pada DynamicObject sehingga Anda dapat membuat "metode semu" yang bermakna yang membantu mereka di luar?
Mengapa jQuery raja sekarang? Karena Resig dan tim mengikuti proses ini, sampai mereka menemukan prinsip sintaksis yang sangat mengurangi jumlah kode JS yang diperlukan untuk bekerja dengan dom dan acara. Prinsip sintaksis itu tidak jelas bagi mereka atau siapa pun ketika mereka mulai. Mereka menemukannya.
Sebagai seorang programmer, itulah panggilan tertinggi Anda. Anda meraba-raba dalam gelap mencoba barang sampai Anda menemukannya. Ketika Anda melakukannya, Anda akan tahu. Dan Anda akan memberi pengguna Anda lompatan produktivitas yang sangat besar . Dan itulah yang dimaksud dengan desain (dalam bidang perangkat lunak).
sumber
Opsi kedua lebih baik karena lebih mudah bagi orang untuk menggunakan (bahkan jika itu hanya Anda), jauh lebih sederhana.
Untuk pengujian unit, saya hanya akan menguji antarmuka bukan internal jika Anda benar-benar ingin kemudian memindahkan internal dari pribadi ke yang dilindungi.
sumber
1. Statis vs contoh
Saya pikir ada pedoman yang sangat jelas tentang apa yang desain OO baik dan apa yang tidak. Masalahnya adalah bahwa blogosphere membuatnya sulit untuk memisahkan yang baik dari yang buruk dan yang buruk. Anda dapat menemukan beberapa jenis referensi yang mendukung bahkan praktek terburuk yang dapat Anda pikirkan.
Dan praktik terburuk yang dapat saya pikirkan adalah Global State, termasuk statika yang Anda sebutkan dan Singleton favorit semua orang. Beberapa kutipan dari artikel klasik Misko Hevery tentang masalah ini .
Apa intinya adalah bahwa Anda tidak boleh memberikan referensi statis untuk apa pun yang memiliki semacam keadaan tersimpan. Satu-satunya tempat saya menggunakan statika adalah untuk konstanta yang disebutkan, dan saya memiliki keraguan tentang hal itu.
2. Metode dengan parameter input dan nilai balik vs. metode tanpa metode
Hal yang perlu Anda sadari adalah bahwa metode yang tidak memiliki parameter input dan parameter output tidak cukup dijamin untuk beroperasi pada semacam keadaan yang disimpan secara internal (jika tidak, apa yang mereka lakukan?). Ada seluruh bahasa yang dibangun berdasarkan gagasan untuk menghindari keadaan tersimpan.
Setiap kali Anda menyimpan status, Anda memiliki kemungkinan untuk efek samping, jadi pastikan Anda selalu menggunakannya dengan penuh pertimbangan. Ini menyiratkan bahwa Anda harus memilih fungsi dengan input dan / atau output yang ditentukan.
Dan, pada kenyataannya, fungsi yang telah menentukan input dan output jauh lebih mudah untuk diuji - Anda tidak harus menjalankan fungsi di sini dan melihat ke sana untuk melihat apa yang terjadi, dan Anda tidak perlu mengatur properti di suatu tempat lain sebelum Anda menjalankan fungsi yang sedang diuji.
Anda juga dapat menggunakan fungsi jenis ini dengan aman sebagai statika. Namun, saya tidak akan melakukannya, karena jika saya kemudian ingin menggunakan implementasi yang sedikit berbeda dari fungsi itu di suatu tempat, daripada memberikan contoh yang berbeda dengan implementasi baru, saya terjebak dengan tidak ada cara untuk mengganti fungsi.
3. Tumpang tindih vs Berbeda
Saya tidak mengerti pertanyaannya. Apa keuntungannya dalam 2 metode yang tumpang tindih?
4. Pribadi vs. Publik
Jangan memaparkan apa pun yang tidak perlu Anda ungkapkan. Namun, saya juga bukan penggemar pribadi. Saya bukan pengembang C #, tetapi pengembang ActionScript. Saya telah menghabiskan banyak waktu dalam kode Kerangka Flex Adobe, yang ditulis sekitar tahun 2007. Dan mereka membuat beberapa pilihan yang sangat buruk tentang apa yang harus dijadikan pribadi, yang membuatnya menjadi semacam mimpi buruk ketika mencoba memperluas Kelas mereka.
Jadi, kecuali jika Anda berpikir Anda adalah arsitek yang lebih baik daripada pengembang Adobe sekitar tahun 2007 (dari pertanyaan Anda, saya akan mengatakan Anda memiliki beberapa tahun lagi sebelum Anda memiliki kesempatan untuk membuat klaim itu), Anda mungkin ingin secara default dilindungi saja. .
Ada beberapa masalah dengan contoh kode Anda yang berarti bahwa mereka tidak dirancang dengan baik, sehingga tidak mungkin untuk memilih A atau B.
Untuk satu hal, Anda mungkin harus memisahkan pembuatan objek dari penggunaannya . Jadi Anda biasanya tidak akan memiliki
new XMLReader()
hak di sebelah tempat itu digunakan.Juga, seperti yang dikatakan @djna, Anda harus merangkum metode yang digunakan dalam penggunaan Pustaka XML Anda, sehingga API Anda (contoh instance) mungkin disederhanakan menjadi:
Saya tidak tahu cara kerja C #, tetapi karena saya telah bekerja dengan sejumlah teknologi web, saya akan curiga bahwa Anda tidak akan selalu dapat langsung mengembalikan dokumen XML (kecuali mungkin sebagai janji atau jenis yang akan datang) objek), tapi saya tidak bisa memberi Anda saran tentang cara menangani beban Asynchronous di C #.
Perhatikan bahwa dengan pendekatan ini, Anda bisa membuat beberapa implementasi yang dapat mengambil parameter yang memberi tahu mereka di mana / apa yang harus dibaca dan mengembalikan objek XML, dan menukar mereka berdasarkan kebutuhan proyek Anda. Misalnya, Anda mungkin membaca langsung dari database, dari toko lokal, atau, seperti dalam contoh asli Anda, dari URL. Anda tidak dapat melakukannya jika menggunakan metode statis.
sumber
Fokus pada perspektif klien.
Metode statis cenderung membatasi evolusi di masa depan, klien kami bekerja dalam hal antarmuka yang disediakan oleh banyak implementasi yang mungkin berbeda.
Masalah utama dengan idiom buka / baca Anda adalah bahwa klien perlu mengetahui urutan metode panggilan, ketika dia hanya ingin menyelesaikan pekerjaan sederhana. Jelas di sini, tetapi di Kelas yang lebih besar jauh dari jelas.
Metode prinsip untuk menguji adalah read (). Metode internal dapat dibuat terlihat untuk menguji program dengan membuatnya tidak publik atau pribadi dan menempatkan tes dalam paket yang sama - tes masih dapat disimpan terpisah dari kode yang dirilis.
sumber
Dalam praktiknya Anda akan menemukan metode statis umumnya terbatas pada kelas utilitas dan tidak boleh mengacaukan objek domain Anda, manajer, pengontrol atau DAO. Metode statis paling berguna ketika semua referensi yang diperlukan dapat secara wajar diteruskan sebagai parameter dan mengemukakan beberapa fungsi yang dapat digunakan kembali di banyak kelas. Jika Anda menemukan diri Anda menggunakan metode statis sebagai solusi untuk memiliki referensi ke objek contoh, tanyakan pada diri sendiri mengapa Anda tidak hanya memiliki referensi itu saja.
Jika Anda tidak membutuhkan parameter pada metode ini, jangan menambahkannya. Sama halnya dengan nilai pengembalian. Dengan mengingat hal ini akan menyederhanakan kode Anda dan memastikan Anda tidak melakukan pengkodean untuk banyak skenario yang akhirnya tidak pernah terjadi.
Merupakan ide bagus untuk mencoba menghindari fungsi yang tumpang tindih. Kadang-kadang bisa sulit, tetapi ketika perubahan logika diperlukan, itu jauh lebih mudah untuk mengubah satu metode yang digunakan kembali, daripada mengubah sejumlah metode dengan fungsi yang sama
Biasanya getter, setter dan konstruktor harus publik. Segala hal lain yang ingin Anda coba jaga kerahasiaannya kecuali ada kasus di mana kelas lain perlu menjalankannya. Menjaga metode default ke pribadi akan membantu mempertahankan Enkapsulasi . Sama berlaku untuk bidang, biasakan untuk pribadi sebagai default
sumber
Saya tidak akan menjawab pertanyaan Anda, tetapi saya pikir ada masalah yang diciptakan oleh istilah yang Anda gunakan. Misalnya
Saya pikir Anda memerlukan XML jadi saya akan membuat objek XML yang dapat dibuat dari tipe teks (Saya tidak tahu C # ... di Jawa itu disebut String). Misalnya
Anda dapat mengujinya dan itu jelas. Kemudian jika Anda memerlukan pabrik, Anda dapat menambahkan metode pabrik (dan itu bisa statis seperti contoh 2 Anda). Misalnya
sumber
Anda dapat mengikuti beberapa aturan sederhana. Ini membantu jika Anda memahami alasan aturan tersebut.
metode statis vs contoh
Untuk metode Anda tidak harus membuat keputusan ini secara sadar. Jika tampaknya metode Anda tidak menggunakan anggota bidang apa pun (penganalisa favorit Anda seharusnya memberi tahu Anda), Anda harus menambahkan kata kunci statis.
metode tanpa parameter atau nilai balik vs metode dengan parameter dan nilai balik
Opsi kedua lebih baik karena ruang lingkup. Anda harus selalu menjaga ruang lingkup Anda ketat. Menjangkau barang yang Anda butuhkan buruk, Anda harus memiliki input, mengerjakannya secara lokal, dan mengembalikan hasilnya. Pilihan pertama Anda buruk karena alasan yang sama variabel global biasanya buruk: mereka bermakna hanya sebagian dari kode Anda tetapi mereka terlihat (dan karenanya berisik) di tempat lain dan dapat dirusak dari mana saja. Ini membuatnya sulit untuk mendapatkan gambaran lengkap tentang logika Anda.
tumpang tindih vs fungsionalitas metode yang berbeda
Saya rasa ini bukan masalah. Metode memanggil metode lain baik-baik saja jika ini memotong tugas menjadi potongan-potongan fungsional yang lebih kecil.
metode pribadi vs publik
Jadikan semuanya pribadi kecuali Anda membutuhkannya untuk umum. Pengguna kelas Anda dapat melakukannya tanpa suara, dia hanya ingin melihat apa yang penting baginya.
sumber