Saya melihat utas ini
Jika kelas "Utilities" jahat, di mana saya harus meletakkan kode generik saya?
dan berpikir mengapa kelas utilitas jahat?
Katakanlah saya memiliki model domain yang terdiri dari puluhan kelas. Saya harus mampu untuk xml-ify instance. Apakah saya membuat metode toXml pada induknya? Apakah saya membuat kelas pembantu MyDomainXmlUtility.toXml? Ini adalah kasus di mana kebutuhan bisnis mencakup seluruh model domain - apakah itu benar-benar termasuk sebagai metode contoh? Bagaimana jika ada sekumpulan metode tambahan pada fungsionalitas xml aplikasi?
design-patterns
software-design
hvgotcodes
sumber
sumber
Jawaban:
Kelas utilitas tidak sepenuhnya jahat, tetapi dapat melanggar prinsip-prinsip yang menyusun desain berorientasi objek yang baik. Dalam desain berorientasi objek yang baik, kebanyakan kelas harus mewakili satu hal dan semua atribut dan operasinya. Jika Anda menjalankan sesuatu, metode itu mungkin harus menjadi anggota dari benda itu.
Namun, ada kalanya Anda dapat menggunakan kelas utilitas untuk mengelompokkan sejumlah metode bersama - contohnya adalah
java.util.Collections
kelas yang menyediakan sejumlah utilitas yang dapat digunakan di Koleksi Java apa pun. Ini tidak spesifik untuk satu jenis Koleksi tertentu, tetapi menerapkan algoritme yang dapat digunakan pada Koleksi apa pun.Sungguh, yang perlu Anda lakukan adalah memikirkan desain Anda dan menentukan di mana cara yang paling masuk akal untuk meletakkan metode. Biasanya, ini sebagai operasi di dalam kelas. Namun, terkadang, ini memang sebagai kelas utilitas. Namun, ketika Anda menggunakan kelas utilitas, jangan hanya memasukkan metode acak ke dalamnya, melainkan, atur metode berdasarkan tujuan dan fungsionalitas.
sumber
Saya pikir konsensus umum adalah bahwa kelas utilitas tidak jahat itu sendiri . Anda hanya perlu menggunakannya dengan bijaksana:
Rancang metode utilitas statis agar umum dan dapat digunakan kembali. Pastikan bahwa mereka tidak memiliki kewarganegaraan; yaitu tidak ada variabel statis.
Jika Anda memiliki banyak metode utilitas, partisi ke dalam kelas-kelas dengan cara yang akan memudahkan pengembang untuk menemukannya.
Jangan gunakan kelas utilitas di mana metode statis atau contoh di kelas domain akan menjadi solusi yang lebih baik. Misalnya, pertimbangkan jika metode dalam kelas dasar abstrak atau kelas pembantu instantiable akan menjadi solusi yang lebih baik.
Untuk Java 8 dan seterusnya, "metode default" di antarmuka mungkin merupakan opsi yang lebih baik daripada kelas utilitas. (Lihat Antarmuka dengan metode default vs kelas Abstrak di Java 8 misalnya.)
Cara lain untuk melihat Pertanyaan ini adalah dengan mengamati bahwa dalam Pertanyaan yang dikutip, "Jika kelas utilitas" jahat "" adalah argumen yang menarik. Ini seperti saya bertanya:
Dalam pertanyaan di atas saya sebenarnya tidak mengatakan bahwa babi dapat terbang ... atau bahwa saya setuju dengan proposisi bahwa mereka dapat terbang.
Pernyataan khas "xyz is evil" adalah alat retoris yang dimaksudkan untuk membuat Anda berpikir dengan mengajukan sudut pandang yang ekstrim. Mereka jarang (jika pernah) dimaksudkan sebagai pernyataan fakta literal.
sumber
Kelas utilitas bermasalah karena gagal mengelompokkan tanggung jawab dengan data yang mendukungnya.
Namun mereka sangat berguna dan saya membangunnya sepanjang waktu baik sebagai struktur permanen atau sebagai batu loncatan selama refaktor yang lebih menyeluruh.
Dari perspektif Kode Bersih , kelas utilitas melanggar Tanggung Jawab Tunggal dan Prinsip Terbuka-Tertutup. Mereka memiliki banyak alasan untuk berubah dan dengan desain tidak dapat diperluas. Mereka seharusnya hanya ada selama refactoring sebagai cruft perantara.
sumber
class
kata kunci digunakan. Itu dukun seperti namespace, itu berjalan seperti namespace - ini adalah satu ...x.equals(y)
karena 1) fakta bahwa ini benar-benar tidak boleh mengubah keadaan apa pun tidak disampaikan (dan saya tidak dapat mengandalkannya tanpa mengetahui penerapannya) 2) Saya tidak pernah bermaksud untuk memasukkanx
" disukai posisi "atau" ditindaklanjuti "dibandingkan dengany
3) Saya tidak ingin mempertimbangkan" identitas "x
atauy
tetapi saya hanya tertarik pada nilai-nilai mereka.Saya kira itu mulai menjadi jahat ketika
1) Terlalu besar (kelompokkan saja ke dalam kategori yang bermakna dalam kasus ini).
2) Metode yang tidak boleh menjadi metode statis
Tapi selama kondisi ini tidak terpenuhi, menurut saya itu sangat berguna.
sumber
Widget.compareTo(Widget widget)
versus statisWidgetUtils.compare(Widget widgetOne, Widget widgetTwo)
. Perbandingan adalah contoh dari sesuatu yang tidak boleh dilakukan secara statis.Aturan praktis
Anda dapat melihat masalah ini dari dua perspektif:
*Util
Metode keseluruhan sering kali merupakan saran dari desain kode yang buruk atau konvensi penamaan yang malas.Contoh 1. Penggunaan
util
kelas / modul dengan benar. Contoh perpustakaan eksternalAnggaplah Anda sedang menulis aplikasi yang mengelola pinjaman dan kartu kredit. Data dari modul ini diekspos melalui layanan web dalam
json
format. Secara teori, Anda dapat secara manual mengonversi objek menjadi string yang akan ada di dalamnyajson
, tetapi itu akan menciptakan kembali roda. Solusi yang benar adalah dengan memasukkan kedua modul perpustakaan eksternal yang digunakan untuk mengonversi objek java ke format yang diinginkan. (dalam contoh gambar saya telah menunjukkan gson )Contoh 2. Penggunaan
util
kelas / modul dengan benar. Menulis sendiriutil
tanpa alasan kepada anggota tim lainnyaSebagai kasus penggunaan, asumsikan bahwa kita perlu melakukan beberapa perhitungan dalam dua modul aplikasi, tetapi keduanya perlu mengetahui kapan ada hari libur nasional di Polandia. Secara teori, Anda dapat membuat kalkulasi ini di dalam modul, tetapi akan lebih baik jika fungsi ini diekstrak ke modul terpisah.
Ini detail kecil, tapi penting. Kelas / modul yang telah Anda tulis tidak disebut
HolidayUtil
, tetapiPolishHolidayCalculator
. Secara fungsional ini adalahutil
kelas, tetapi kami telah berhasil menghindari kata umum.sumber
Kelas utilitas buruk karena berarti Anda terlalu malas untuk memikirkan nama yang lebih baik untuk kelas tersebut :)
Itu dikatakan, saya malas. Terkadang Anda hanya perlu menyelesaikan pekerjaan dan pikiran Anda kosong .. saat itulah kelas "Utilitas" mulai masuk.
sumber
Melihat kembali pertanyaan ini sekarang, saya akan mengatakan bahwa metode ekstensi C # benar-benar menghancurkan kebutuhan akan kelas utilitas. Tetapi tidak semua bahasa memiliki konstruksi yang begitu jenius.
Anda juga memiliki JavaScript, di mana Anda bisa menambahkan fungsi baru langsung ke objek yang ada.
Tapi saya tidak yakin benar-benar ada cara elegan untuk menyelesaikan masalah ini dalam bahasa yang lebih lama seperti C ++ ...
Kode OO yang baik agak sulit untuk ditulis, dan sulit ditemukan karena menulis OO yang baik membutuhkan lebih banyak waktu / pengetahuan daripada menulis kode fungsional yang layak.
Dan jika anggaran Anda terbatas, atasan Anda tidak selalu senang melihat Anda menghabiskan sepanjang hari menulis banyak kelas ...
sumber
Saya tidak sepenuhnya setuju bahwa kelas utilitas itu jahat.
Meskipun kelas utilitas dapat melanggar prinsip-prinsip OO dalam beberapa hal, mereka tidak selalu buruk.
Misalnya, bayangkan Anda menginginkan fungsi yang akan membersihkan string dari semua substring yang cocok dengan nilai
x
.stl c ++ (seperti yang sekarang) tidak mendukung ini secara langsung.
Anda dapat membuat ekstensi polimorfik
std::string
.Tetapi masalahnya adalah, apakah Anda benar-benar ingin SETIAP string yang Anda gunakan dalam proyek Anda menjadi kelas string yang diperluas?
Ada kalanya OO tidak masuk akal, dan ini salah satunya. Kami ingin program kami kompatibel dengan program lain, jadi kami akan tetap menggunakan
std::string
dan membuat kelasStringUtil_
(atau sesuatu).Saya akan mengatakan yang terbaik jika Anda tetap dengan satu util per kelas. Menurut saya konyol memiliki satu util untuk semua kelas atau banyak utilitas untuk satu kelas.
sumber
Sangat mudah untuk memberi merek pada suatu utilitas hanya karena perancang tidak dapat memikirkan tempat yang tepat untuk meletakkan kode. Seringkali hanya ada sedikit "utilitas" yang benar.
Sebagai aturan praktis, saya biasanya menyimpan kode dalam paket tempat kode tersebut pertama kali digunakan, dan kemudian hanya melakukan refactor ke tempat yang lebih umum jika saya menemukan bahwa nantinya kode tersebut benar-benar diperlukan di tempat lain. Satu-satunya pengecualian adalah jika saya sudah memiliki paket yang melakukan fungsi serupa / terkait, dan kode paling cocok di sana.
sumber
Kelas utilitas yang berisi metode statis stateless dapat berguna. Ini seringkali sangat mudah untuk pengujian unit.
sumber
Dengan Java 8 Anda dapat menggunakan metode statis di antarmuka ... masalah terpecahkan.
sumber
Kebanyakan kelas Util buruk karena:
Ada beberapa analogi pustaka statis vs dinamis.
sumber
Ketika saya tidak dapat menambahkan metode ke kelas (katakanlah,
Account
dikunci terhadap perubahan oleh Pengembang Jr), saya hanya menambahkan beberapa metode statis ke kelas Utilitas saya seperti:sumber
Account
file. Atau lebih baik, gunakan sistem kontrol sumber tanpa penguncian.Account
file tersebut dikunci sehingga Jr. Pengembang tidak dapat mengubahnya. Sebagai seorang Jr Developer, untuk menyiasatinya, dia melakukan seperti di atas. Meskipun demikian, masih lebih baik mendapatkan akses tulis ke file dan melakukannya dengan benar.Kelas utilitas tidak selalu jahat. Tetapi mereka seharusnya hanya berisi metode yang umum di berbagai fungsi. Jika ada metode yang hanya dapat digunakan di antara sejumlah kelas, pertimbangkan untuk membuat kelas abstrak sebagai induk bersama dan letakkan metode di dalamnya.
sumber