Saya baru-baru ini dilemparkan ke proyek aplikasi web Java, dan saya telah menemukan sejumlah kelas yang mengikuti jenis format ini:
public class MyThingy {
private final int p1;
private final String p2;
…
public MyThingy (int p1, String p2, …) {
this.p1 = p1;
this.p2 = p2;
…
}
public static void doSomething(int p1, String p2, …) throws Throwable {
final MyThingy myThingy = new MyThingy(p1, p2, …);
myThingy.execute();
}
private void execute() throws Throwable {
//do stuff
}
}
Sepertinya ini bisa diselesaikan dengan kode berikut, yang bagi saya tampaknya lebih mudah dibaca.
public class MyThingy {
public static void doSomething (int p1, String p2, …) throws Throwable {
//do stuff
}
}
Satu-satunya keuntungan yang bisa saya lihat dari melakukannya dengan cara pertama, adalah bahwa jika Anda harus memecah eksekusi () menjadi bagian-bagian yang lebih kecil, mereka semua dapat berbagi parameter awal tanpa harus secara eksplisit membagikannya. Tapi ini mungkin hanya menguntungkan pemodal malas, karena menjadi sulit bagi pembaca untuk mengetahui metode mana yang membutuhkan parameter mana dan kapan nilainya dapat diubah (mirip dengan variabel global.)
Apakah ada sesuatu yang saya lewatkan? Threading, kinerja?
Sunting: Saya seharusnya telah menyebutkan, meskipun konstruktor bersifat publik, tidak disebut. Satu-satunya penggunaan adalah seperti ini:
MyThingy.doSomething(p1, p2...);
Selain dari itu sendiri yang bermasalah untuk pengujian, saya tidak bisa melihat alasan untuk tidak menempatkan logika eksekusi () langsung ke doSomething (). Bahkan jika kita harus menyingkirkan fungsi statis, konstruktor masih tidak masuk akal bagi saya; Saya pikir parameter harus diteruskan langsung ke metode yang akan menggunakannya.
sumber
throws Throwable
adalah praktik yang buruk, itu harus setidaknyathrows Exception
, atau sesuatu yang lebih spesifik, jika memungkinkan. Dan, karena praktik buruk biasanya muncul bersamaan, saya akan mengatakan bahwa templat kode ini hanyalah praktik buruk lainnya.new(...)
+execute()
dalam satu panggilan.final
). Metode statis adalah satu-satunya API ke objek karena semua anggota bersifat pribadi. Hanya dalam kode yang telah Anda bagikan, saya tidak melihat manfaatnya dengan membuatexecute
metode statis dengan mengambil p1, p2, ....Jawaban:
Saya pikir intuisi Anda tentang masalah ini benar.
Jadi, haruskah Anda menggunakannya ?
Bahkan, yang dipermasalahkan bukan hanya "metode sebagai kelas" murni. Di kelas normal, Anda mungkin tergoda untuk membuat bidang yang tidak memiliki pemanggilan metode publik di sela-sela. Mereka hanya digunakan untuk menghindari melewati parameter antara metode pribadi. Di masa lalu, saya mencoba untuk menghindarinya sama sekali, tetapi kemudian menyadari bahwa daftar parameter panjang juga menyedot.
Saya mencoba untuk menghindari "kelas metode" murni karena saya pikir mereka datang dengan banyak beban mental (begitu banyak potensi potensial). (Saya juga bersandar pada bidang sekali pakai di kelas reguler.) Tetapi jika ada satu ton variabel untuk dibagikan, kemenangan dalam kebersihan kode mungkin sepadan.
Saya mencoba menggunakan kelas ketika ada poin untuk itu, dan sebenarnya biasanya mudah untuk membayangkannya. Mungkin di masa depan Anda akan memperluas kelas dengan implementasi tambahan. Mungkin instance dapat dianggap sebagai objek fungsi yang ingin Anda inisialisasi dan diedarkan. Dan kemudian, kelas tidak lagi menjadi "metode kelas" pseudo-OO.
sumber
Tipuan ekstra melalui panggilan metode statis memisahkan kekhawatiran tentang bagaimana suatu objek dibuat dari kode yang menggunakan objek. Apa yang Anda miliki di sini adalah sesuatu yang sangat mirip dengan metode pabrik sederhana (itu sebenarnya tidak mengembalikan objek, tetapi tipuan pembuatan objek adalah sama).
Ini bisa berguna jika Anda perlu mengontrol tipe objek yang dibuat. Dalam contoh sederhana ini tidak ada keputusan untuk dibuat, tetapi akan mudah untuk menambahkan logika itu.
Apa arti kode statis untuk penelepon adalah "Saya perlu melakukan sesuatu dengan keadaan ini tetapi tidak tahu bagaimana mendelegasikan." Metode statis kemudian dapat mendelegasikan ke implementasi yang tepat berdasarkan objek yang disediakan.
Mungkin ketika menjalankan dalam unit test ada objek tiruan yang digunakan. Mungkin berdasarkan parameter objek yang berbeda dapat ditukar dalam mengimplementasikan algoritma yang berbeda untuk melakukan apa pun yang perlu dilakukan. Dengan melokalkan kode itu ke satu lokasi, keputusan dapat dibuat di satu tempat dan bukan di banyak tempat.
Mengingat bagaimana pertanyaan Anda diucapkan dan fakta bahwa tidak ada keputusan konstruksi dibuat dalam metode statis, saya merasa ini mungkin hanya kasus over-engineering. Sebagian besar kode tidak perlu didelegasikan ke pabrik. Fakta bahwa Anda terus menemukan kode seperti ini yang tidak membuat keputusan seperti yang saya harapkan metode seperti pabrik statis lakukan memberitahu saya seseorang membaca buku GoF dan mengamuk.
sumber
Nah, jika contoh kedua Anda (menunjukkan kode lengkap ) terlihat seperti ini:
maka Anda masih akan membutuhkan konstruktor
yang pada gilirannya mengatur
dan sekarang Anda kembali ke tempat Anda mulai.
Anda bisa, tentu saja, hanya menghilangkan konstruktor dan pergi dengan getter dan setter sebagai gantinya
... tetapi ini akan menyulitkan pemanggilan metode statis Anda, karena Anda sekarang akan memerlukan beberapa baris kode untuk memanggil setter terlebih dahulu sebelum memanggil metode statis Anda, di mana satu baris yang menggunakan panggilan konstruktor akan cukup.
Tentu saja, ini hanya berfungsi jika variabel anggota Anda tidak
final
. Karena itu, Anda masih memerlukan konstruktor.sumber
final
variabel. Ini hanya dapat diinisialisasi sekali.Biasanya sebuah kelas memiliki banyak metode instance, dan begitu objek dibuat, implementasi eksekusi dapat mengambil keuntungan dari semua metode instance ini. Jika Anda menolak untuk membuat objek, semua metode instance ini tidak berguna.
sumber
execute
. Jadi, bertanya mengapa tidak menjelaskan semuanya.