Dalam basis kode Java kami, saya terus melihat pola berikut:
/**
This is a stateless utility class
that groups useful foo-related operations, often with side effects.
*/
public class FooUtil {
public int foo(...) {...}
public void bar(...) {...}
}
/**
This class does applied foo-related things.
*/
class FooSomething {
int DoBusinessWithFoo(FooUtil fooUtil, ...) {
if (fooUtil.foo(...)) fooUtil.bar(...);
}
}
Yang mengganggu saya adalah bahwa saya harus melewati contoh di FooUtil
mana - mana, karena pengujian.
- Saya tidak dapat membuat
FooUtil
metode statis, karena saya tidak akan dapat mengejek mereka untuk pengujian keduanyaFooUtil
dan kelas kliennya. - Saya tidak dapat membuat contoh
FooUtil
di tempat konsumsi dengannew
, lagi karena saya tidak akan dapat mengejeknya untuk pengujian.
Saya kira bahwa taruhan terbaik saya adalah menggunakan injeksi (dan saya lakukan), tetapi ia menambahkan kerepotan sendiri. Juga, melewatkan beberapa instance util mengembang ukuran daftar parameter metode.
Apakah ada cara untuk menangani ini dengan lebih baik yang tidak saya lihat?
Pembaruan: karena kelas utilitas tidak memiliki kewarganegaraan, saya mungkin dapat menambahkan anggota statis statis INSTANCE
, atau getInstance()
metode statis , sambil mempertahankan kemampuan untuk memperbarui bidang statis yang mendasari kelas untuk pengujian. Sepertinya tidak super bersih juga.
FooUtil
metode harus dimasukkan ke dalamFooSomething
, mungkin ada propertiFooSomething
yang harus diubah / diperpanjang sehinggaFooUtil
metode tidak diperlukan lagi. Tolong beri kami contoh yang lebih nyata tentang apa yangFooSomething
membantu kami memberikan jawaban yang baik untuk pertanyaan ini.Jawaban:
Pertama-tama izinkan saya mengatakan bahwa ada pendekatan pemrograman yang berbeda untuk masalah yang berbeda. Untuk pekerjaan saya, saya lebih suka desain OO yang kuat untuk orginaisasi dan pemeliharaan dan jawaban saya mencerminkan hal ini. Pendekatan fungsional akan memiliki jawaban yang sangat berbeda.
Saya cenderung menemukan bahwa sebagian besar kelas utilitas dibuat karena objek metode seharusnya tidak ada. Ini hampir selalu berasal dari salah satu dari dua kasus, baik seseorang melewati koleksi di sekitar atau seseorang melewati kacang (Ini sering disebut POJO tapi saya percaya banyak setter dan getter digambarkan sebagai kacang).
Ketika Anda memiliki koleksi yang Anda bagikan, harus ada kode yang ingin menjadi bagian dari koleksi itu, dan ini akhirnya ditaburkan di seluruh sistem Anda dan akhirnya dikumpulkan ke dalam kelas utilitas.
Saran saya adalah untuk membungkus koleksi Anda (Atau kacang-kacangan) dengan data lain yang terkait erat ke dalam kelas baru dan memasukkan kode "utilitas" ke objek yang sebenarnya.
Anda dapat memperluas koleksi dan menambahkan metode di sana, tetapi Anda kehilangan kontrol atas keadaan objek Anda dengan cara itu - saya sarankan Anda merangkum sepenuhnya dan hanya mengekspos metode logika bisnis yang diperlukan (Pikirkan "Jangan minta benda Anda untuk data mereka, berikan perintah objek Anda dan biarkan mereka bertindak pada data pribadi mereka ", penyewa OO yang penting dan yang, ketika Anda memikirkannya, membutuhkan pendekatan yang saya sarankan di sini).
"Pembungkus" ini berguna untuk objek perpustakaan tujuan umum yang menyimpan data tetapi Anda tidak dapat menambahkan kode - Memasukkan kode dengan data yang dimanipulasi adalah konsep utama lain dalam desain OO.
Ada banyak gaya pengkodean di mana konsep pembungkus ini akan menjadi ide yang buruk - yang ingin menulis seluruh kelas ketika hanya menerapkan skrip atau tes satu kali? Tapi saya pikir enkapsulasi dari setiap jenis / koleksi dasar yang tidak dapat Anda tambahkan kode untuk diri sendiri adalah wajib untuk OO.
sumber
Anda bisa menggunakan pola Provider dan menyuntikkan Anda
FooSomething
denganFooUtilProvider
objek (bisa dalam konstruktor; hanya sekali).FooUtilProvider
hanya akan memiliki satu metode:FooUtils get();
. Kelas kemudian akan menggunakanFooUtils
instance apa pun yang disediakannya.Nah, itu satu langkah lagi dari menggunakan kerangka kerja Dependency Injection, saat Anda hanya perlu memasang cointainer DI dua kali: untuk kode produksi, dan untuk suite pengujian Anda. Anda hanya mengikat
FooUtils
antarmuka dengan salah satuRealFooUtils
atauMockedFooUtils
, dan sisanya terjadi secara otomatis. Setiap objek yang bergantung padaFooUtilsProvider
mendapatkan versi yang tepatFooUtils
.sumber