Kadang-kadang saya membuat kelas 'Util' yang utamanya berfungsi untuk menampung metode dan nilai yang tampaknya tidak benar-benar dimiliki di tempat lain. Tetapi setiap kali saya membuat salah satu kelas ini, saya pikir "uh-oh, saya akan menyesal nanti ...", karena saya membaca di suatu tempat bahwa itu buruk.
Tetapi di sisi lain, tampaknya ada dua kasus yang menarik (setidaknya bagi saya) untuk mereka:
- rahasia implementasi yang digunakan di banyak kelas dalam satu paket
- menyediakan fungsionalitas yang berguna untuk menambah kelas, tanpa mengacaukan antarmuka
Apakah saya sedang menuju kehancuran? Apa kamu bilang !! Haruskah saya refactor?
Util
atas nama kelas Anda. Masalah terpecahkan.SomethingUtil
agak malas dan hanya mengaburkan tujuan sebenarnya dari kelas - sama dengan kelas yang bernamaSomethingManager
atauSomethingService
. Jika kelas itu memiliki satu tanggung jawab, itu harus mudah untuk memberinya nama yang bermakna. Jika tidak, itulah masalah sebenarnya yang harus dihadapi ...Util
, meskipun jelas saya tidak berharap bahwa itu akan terpaku pada dan sisa pertanyaan diabaikan ...Jawaban:
Desain OO modern menerima bahwa tidak semuanya adalah objek. Beberapa hal adalah perilaku, atau formula, dan beberapa di antaranya tidak memiliki keadaan. Ada baiknya memodelkan hal-hal ini sebagai fungsi murni untuk mendapatkan manfaat dari desain itu.
Java dan C # (dan lainnya) mengharuskan Anda membuat kelas util dan melompati lingkaran itu untuk melakukannya. Mengganggu, tetapi bukan akhir dari dunia; dan tidak terlalu merepotkan dari perspektif desain.
sumber
Tidak pernah berkata tidak"
Saya tidak berpikir itu selalu buruk, itu hanya buruk jika Anda melakukannya dengan buruk dan menyalahgunakannya.
Kita Semua Membutuhkan Alat dan Utilitas
Sebagai permulaan, kita semua menggunakan beberapa perpustakaan yang kadang-kadang dianggap hampir di mana-mana dan harus dimiliki. Misalnya, di dunia Java, Google Guava atau beberapa Apache Commons ( Apache Commons Lang , Apache Commons Collections , dll ...).
Jadi jelas ada kebutuhan untuk ini.
Hindari Kata-Kata Sulit, Duplikasi, dan Perkenalan Bug
Jika Anda berpikir tentang ini cukup banyak hanya sekelompok besar dari
Util
kelas - kelas ini Anda jelaskan, kecuali seseorang berusaha keras untuk membuat mereka (relatif) benar, dan mereka telah diuji - waktu dan sangat terbelalak oleh orang lain.Jadi saya akan mengatakan aturan pertama ketika merasakan gatal untuk menulis
Util
kelas adalah untuk memeriksa bahwaUtil
kelas sebenarnya belum ada.Satu-satunya argumen balasan yang saya lihat adalah ketika Anda ingin membatasi dependensi Anda karena:
Tetapi kedua hal ini dapat diatasi dengan mengemas ulang lib menggunakan ProGuard atau yang setara, atau memisahkannya sendiri (untuk pengguna Maven , plugin maven-shade-plugin menawarkan beberapa pola penyaringan untuk mengintegrasikan ini sebagai bagian dari build Anda).
Jadi, jika itu dalam lib dan cocok dengan use case Anda, dan tidak ada tolok ukur yang memberi tahu Anda sebaliknya, gunakan itu. Jika sedikit berbeda dari apa yang Anda miliki, perluas (jika mungkin) atau perluas, atau dalam upaya terakhir tulis ulang.
Konvensi Penamaan
Namun, sejauh ini dalam jawaban ini saya menyebut mereka
Util
seperti Anda. Jangan sebutkan itu.Beri mereka nama yang berarti. Ambil Google Guava sebagai (sangat, sangat) contoh yang baik dari apa yang harus dilakukan, dan bayangkan bahwa
com.google.guava
namespace sebenarnya adalahutil
root Anda .Panggil paket Anda
util
, paling buruk, tetapi bukan kelas. Jika berurusan denganString
objek dan manipulasi konstruksi string, sebut sajaStrings
, bukanStringUtils
(maaf, Apache Commons Lang - Saya masih suka dan menggunakan Anda!). Jika itu melakukan sesuatu yang spesifik, pilih nama kelas tertentu (sepertiSplitter
atauJoiner
).Unit-Test
Jika Anda harus menggunakan utilitas ini untuk menulis, pastikan untuk mengujinya. Hal yang baik tentang utilitas adalah bahwa mereka biasanya merupakan komponen yang mandiri, yang mengambil input spesifik dan mengembalikan output spesifik. Itulah konsepnya. Jadi tidak ada alasan untuk tidak mengujinya.
Selain itu, pengujian unit akan memungkinkan Anda untuk menentukan dan mendokumentasikan kontrak API mereka. Jika tes gagal, Anda mengubah sesuatu dengan cara yang salah, atau itu berarti Anda mencoba mengubah kontrak API Anda (atau bahwa tes awal Anda adalah omong kosong - belajarlah darinya, dan jangan lakukan lagi) .
Desain API
Keputusan desain yang akan Anda ambil untuk API ini akan mengikuti Anda sejak lama, mungkin. Jadi, meski tidak menghabiskan berjam-jam untuk menulis
Splitter
-kloning, berhati-hatilah dengan cara Anda mendekati masalah ini.Tanyakan kepada diri Anda beberapa pertanyaan:
Anda ingin utilitas ini mencakup banyak kasus penggunaan, menjadi kuat, stabil, terdokumentasi dengan baik, mengikuti prinsip paling tidak mengejutkan, dan mandiri. Idealnya, setiap sub-paket utilitas Anda, atau setidaknya seluruh paket utilitas Anda, dapat diekspor ke bundel agar mudah digunakan kembali.
Seperti biasa, pelajari dari para raksasa di sini:
util
Paket Java (yang berisi perpustakaan Collections) dan .Net yang setara ,Ya, banyak dari ini memiliki penekanan pada koleksi dan struktur data, tapi jangan bilang itu bukan di mana atau untuk apa Anda biasanya akan menerapkan sebagian besar utilitas Anda, secara langsung atau tidak langsung.
sumber
If deals with String objects and manipulation of string constructs, call it Strings, not StringUtils
StringsCollectionTypeHere
jika Anda menginginkan implementasi konkret. Atau nama yang lebih spesifik jika string ini memiliki makna khusus dalam konteks aplikasi Anda. Untuk kasus khusus ini, Guava menggunakanStrings
untuk helper terkait-string, yang bertentangan denganStringUtils
Commons Lang. Saya merasa ini benar-benar dapat diterima, itu hanya berarti bagi saya bahwa kelas menanganiString
objek atau adalah kelas tujuan umum untuk mengelola Strings.NameUtils
hal-hal menggangguku tanpa akhir karena jika ia duduk di bawah nama paket yang diberi label dengan jelas, saya sudah tahu itu adalah kelas utilitas (dan jika tidak, akan mencari tahu dengan cepat dari melihat API). Ini sebagai menjengkelkan bagi saya sebagai orang menyatakan hal-hal sebagaiSomethingInterface
,ISomething
, atauSomethingImpl
. Saya agak OK dengan artefak seperti itu ketika coding di C dan tidak menggunakan IDE. Hari ini saya secara umum tidak membutuhkan hal-hal seperti itu.Kelas Util tidak kohesif dan, umumnya, desain buruk karena kelas harus memiliki alasan tunggal untuk berubah (Prinsip Responsabilitas Tunggal).
Namun, saya telah melihat "util" kelas dalam sangat Java API, seperti:
Math
,Collections
danArrays
.Pada kenyataannya, ini adalah kelas utilitas tetapi semua metode mereka terkait dengan satu tema, satu memiliki operasi matematika, satu memiliki metode untuk memanipulasi koleksi dan yang lainnya untuk memanipulasi array.
Cobalah tidak, tidak memiliki metode yang sama sekali tidak terkait dalam kelas utilitas. Jika itu masalahnya, kemungkinan Anda juga bisa menempatkannya di tempat yang seharusnya.
Jika harus menggunakan kelas maka cobalah untuk dipisahkan dengan tema seperti Java
Math
,Collections
danArrays
. Setidaknya, itu menunjukkan beberapa niat desain bahkan ketika mereka hanya ruang nama.I untuk satu, selalu menghindari kelas utilitas dan tidak pernah memiliki kebutuhan untuk membuatnya.
sumber
Math
atauArrays
menunjukkan setidaknya beberapa niat desain.Sangat dapat diterima untuk menggunakan kelas util , meskipun saya lebih suka istilah itu
ClassNameHelper
. .NET BCL bahkan memiliki kelas pembantu di dalamnya. Hal yang paling penting untuk diingat, adalah mendokumentasikan tujuan kelas secara menyeluruh, serta setiap metode pembantu individu, dan untuk membuatnya menjadi kode yang dapat dikelola dengan kualitas tinggi.Dan jangan terbawa oleh kelas pembantu.
sumber
Saya menggunakan pendekatan dua tingkat. Kelas "Global" dalam paket "util" (folder). Untuk sesuatu yang masuk ke kelas "Global" atau paket "util", itu harus:
Contoh yang lulus tes ini:
Berikut adalah contoh metode pembantu yang sangat kecil, benar-benar independen dari aplikasi lainnya:
Melihat ini saya bisa melihat bug bahwa 21 harus "21", 22 harus "22", dll. Tapi itu intinya.
Jika salah satu dari metode penolong itu tumbuh atau menjadi rumit, ia harus dipindahkan ke kelasnya sendiri dalam paket util. Jika dua atau lebih kelas pembantu dalam paket util terkait satu sama lain, mereka harus dipindahkan ke paket mereka sendiri. Jika metode konstan atau helper ternyata terkait dengan bagian spesifik aplikasi Anda, itu harus dipindahkan ke sana.
Anda harus dapat membenarkan mengapa tidak ada tempat yang lebih baik untuk semua yang Anda tempel di kelas Globals atau paket util dan Anda harus membersihkannya secara berkala menggunakan tes di atas. Jika tidak, Anda hanya membuat kekacauan.
sumber