Terlalu Banyak Parameter dalam Metode Java, Bagian 6: Metode Kembali

Dalam rangkaian posting saat ini yang saya tulis tentang pengurangan jumlah parameter yang diperlukan untuk memanggil metode dan konstruktor Java, sejauh ini saya telah berfokus pada pendekatan yang secara langsung memengaruhi parameter itu sendiri (tipe khusus, objek parameter, pola pembangun, kelebihan metode, dan metode penamaan). Mengingat ini, mungkin tampak mengejutkan bagi saya untuk mencurahkan posting dalam seri ini tentang bagaimana metode Java memberikan nilai yang dikembalikan. Namun, nilai kembalian metode dapat memengaruhi parameter yang diterima metode saat pengembang memilih untuk memberikan nilai "kembalian" dengan menyetel atau mengubah parameter yang disediakan daripada atau sebagai tambahan pada mekanisme pengembalian metode yang lebih tradisional.

"Cara tradisional" di mana metode non-konstruktor mengembalikan nilai bisa ditentukan dalam tanda tangan metode. Pendekatan yang paling umum dikenal untuk mengembalikan nilai dari metode Java adalah melalui tipe pengembalian yang dideklarasikan. Ini sering kali bekerja dengan baik, tetapi salah satu kekecewaan yang paling sering terjadi adalah karena hanya diizinkan untuk mengembalikan satu nilai dari metode Java ..

Mekanisme penanganan pengecualian Java juga merupakan pendekatan lain untuk mempertahankan "hasil" metode bagi pemanggil. Pengecualian yang dicentang, khususnya, diiklankan ke pemanggil melalui klausa lemparan. Faktanya, Jim Waldo, dalam bukunya Java: The Good Parts, menyatakan bahwa lebih mudah untuk memahami pengecualian Java ketika seseorang menganggap pengecualian Java sebagai tipe metode lain yang kembali terbatas pada tipe Throwable.

Meskipun tipe kembalian metode dan pengecualian yang ditampilkan dimaksudkan sebagai pendekatan utama metode untuk mengembalikan informasi ke pemanggil, terkadang Anda tergoda untuk mengembalikan data atau status melalui parameter yang diteruskan ke metode. Ketika suatu metode perlu mengembalikan lebih dari satu bagian informasi, pengembalian nilai tunggal metode Java tampaknya membatasi. Meskipun pengecualian memberikan cara lain untuk berkomunikasi kembali ke pemanggil, tampaknya hampir secara universal disepakati bahwa pengecualian hanya boleh digunakan untuk melaporkan situasi luar biasa dan bukan untuk melaporkan data "normal" atau digunakan dalam aliran kontrol. Mengingat bahwa hanya satu objek atau primitif yang dapat dikembalikan dari suatu metode dan pengecualian itu hanya memungkinkan pengembalian aThrowable dan sebaiknya hanya digunakan untuk melaporkan situasi luar biasa, ini menjadi semakin menarik bagi pengembang Java untuk membajak parameter sebagai rute alternatif untuk mengembalikan data ke pemanggil.

Teknik yang dapat digunakan pengembang untuk menerapkan parameter metode sebagai pembawa untuk data yang dikembalikan adalah dengan menerima parameter yang bisa berubah dan untuk mengubah status objek yang diteruskan. Objek yang bisa berubah ini dapat diubah isinya dengan metode dan kemudian pemanggil dapat mengakses objek yang disediakan untuk menentukan pengaturan status barunya yang telah diterapkan oleh metode yang dipanggil. Meskipun ini dapat dilakukan dengan objek yang bisa berubah, koleksi tampak sangat menarik bagi pengembang yang mencoba meneruskan nilai kembali ke pemanggil melalui parameter.

Ada beberapa kerugian untuk meneruskan status kembali ke yang dipanggil melalui parameter yang disediakan. Pendekatan ini sering melanggar prinsip yang paling tidak mengherankan karena sebagian besar pengembang Java mungkin mengharapkan parameter berupa INcoming daripada OUTgoing (dan Java tidak menyediakan dukungan kode apa pun untuk menentukan perbedaannya). Bob Martin mengatakannya seperti ini dalam bukunya Clean Code, "Secara umum, argumen keluaran harus dihindari." Kerugian lain dari menggunakan argumen sebagai sarana metode untuk menyediakan status atau keluaran ke pemanggil adalah hal ini menambah kekacauan argumen yang diteruskan ke sebuah metode. Dengan pemikiran ini, sisa posting ini berfokus pada alternatif untuk mengembalikan beberapa nilai melalui parameter yang diteruskan.

Meskipun metode Java hanya dapat mengembalikan satu objek atau primitif, ini sebenarnya bukan batasan ketika seseorang menganggap bahwa objek bisa menjadi apa saja yang kita inginkan. Ada beberapa pendekatan yang pernah saya lihat tetapi tidak saya rekomendasikan. Salah satunya adalah mengembalikan array atau kumpulan instance Object dengan masing-masingObjectmenjadi "hal" yang berbeda dan berbeda dan seringkali tidak berhubungan. Misalnya, metode mungkin mengembalikan tiga nilai sebagai tiga elemen dari sebuah larik atau kumpulan. Variasi dari pendekatan ini adalah menggunakan pasangan tupel atau tupel berukuran n untuk mengembalikan beberapa nilai terkait. Variasi lain pada pendekatan ini adalah mengembalikan Peta Java yang memetakan kunci arbitrer ke nilai yang terkait. Seperti solusi lainnya, pendekatan ini memberikan beban yang tidak semestinya pada klien untuk mengetahui apa itu kunci dan untuk mengakses nilai peta melalui kunci tersebut.

Daftar kode berikutnya berisi beberapa pendekatan yang kurang menarik ini untuk mengembalikan beberapa nilai tanpa membajak parameter metode untuk mengembalikan beberapa nilai.

Mengembalikan Banyak Nilai melalui Struktur Data Generik

 // =============================================================== // NOTE: These examples are intended solely to illustrate a point // and are NOT recommended for production code. // =============================================================== /** * Provide movie information. * * @return Movie information in form of an array where details are mapped to * elements with the following indexes in the array: * 0 : Movie Title * 1 : Year Released * 2 : Director * 3 : Rating */ public Object[] getMovieInformation() { final Object[] movieDetails = {"World War Z", 2013, "Marc Forster", "PG-13"}; return movieDetails; } /** * Provide movie information. * * @return Movie information in form of a List where details are provided * in this order: Movie Title, Year Released, Director, Rating. */ public List getMovieDetails() { return Arrays.asList("Ender's Game", 2013, "Gavin Hood", "PG-13"); } /** * Provide movie information. * * @return Movie information in Map form. Characteristics of the movie can * be acquired by looking in the map for these key elements: "Title", "Year", * "Director", and "Rating"./ */ public Map getMovieDetailsMap() { final HashMap map = new HashMap(); map.put("Title", "Despicable Me 2"); map.put("Year", 2013); map.put("Director", "Pierre Coffin and Chris Renaud"); map.put("Rating", "PG"); return map; } 

Pendekatan yang ditampilkan di atas memang memenuhi maksud untuk tidak meneruskan data kembali ke pemanggil melalui parameter metode yang dipanggil, tetapi masih ada beban yang tidak perlu ditempatkan pada pemanggil untuk mengetahui detail mendalam dari struktur data yang dikembalikan. Sangat menyenangkan untuk mengurangi jumlah parameter ke metode dan tidak melanggar prinsip paling tidak mengejutkan, tetapi tidak baik meminta klien untuk mengetahui seluk-beluk struktur data yang kompleks.

Saya lebih suka menulis objek kustom untuk pengembalian saya ketika saya perlu mengembalikan lebih dari satu nilai. Ini sedikit lebih banyak pekerjaan daripada menggunakan array, koleksi, atau struktur tuple, tetapi jumlah kerja ekstra yang sangat kecil (biasanya beberapa menit dengan Java IDE modern) terbayar dengan keterbacaan dan kefasihan yang tidak tersedia dengan pendekatan yang lebih umum ini. Daripada harus menjelaskan dengan Javadoc atau meminta pengguna kode saya untuk membaca kode saya dengan hati-hati untuk mengetahui parameter mana yang disediakan dalam urutan mana dalam larik atau koleksi atau nilai mana yang ada di tupel, objek pengembalian khusus saya dapat memiliki metode yang ditentukan pada mereka yang memberi tahu klien dengan tepat apa yang mereka sediakan.

Cuplikan kode berikut menggambarkan Moviekelas sederhana yang sebagian besar dihasilkan oleh NetBeans yang dapat digunakan sebagai jenis kembalian bersama dengan kode yang dapat mengembalikan instance kelas tersebut daripada struktur data yang lebih umum dan kurang dapat dibaca.

Movie.java

package dustin.examples; import java.util.Objects; /** * Simple Movie class to demonstrate how easy it is to provide multiple values * in a single Java method return and provide readability to the client. * * @author Dustin */ public class Movie { private final String movieTitle; private final int yearReleased; private final String movieDirectorName; private final String movieRating; public Movie(String movieTitle, int yearReleased, String movieDirectorName, String movieRating) { this.movieTitle = movieTitle; this.yearReleased = yearReleased; this.movieDirectorName = movieDirectorName; this.movieRating = movieRating; } public String getMovieTitle() { return movieTitle; } public int getYearReleased() { return yearReleased; } public String getMovieDirectorName() { return movieDirectorName; } public String getMovieRating() { return movieRating; } @Override public int hashCode() { int hash = 3; hash = 89 * hash + Objects.hashCode(this.movieTitle); hash = 89 * hash + this.yearReleased; hash = 89 * hash + Objects.hashCode(this.movieDirectorName); hash = 89 * hash + Objects.hashCode(this.movieRating); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Movie other = (Movie) obj; if (!Objects.equals(this.movieTitle, other.movieTitle)) { return false; } if (this.yearReleased != other.yearReleased) { return false; } if (!Objects.equals(this.movieDirectorName, other.movieDirectorName)) { return false; } if (!Objects.equals(this.movieRating, other.movieRating)) { return false; } return true; } @Override public String toString() { return "Movie{" + "movieTitle=" + movieTitle + ", yearReleased=" + yearReleased + ", movieDirectorName=" + movieDirectorName + ", movieRating=" + movieRating + '}'; } } 

Mengembalikan Banyak Detail dalam Satu Objek

 /** * Provide movie information. * * @return Movie information. */ public Movie getMovieInfo() { return new Movie("Oblivion", 2013, "Joseph Kosinski", "PG-13"); } 

Penulisan sederhana dari Moviekelas memakan waktu sekitar 5 menit. Saya menggunakan wizard pembuatan kelas NetBeans untuk memilih nama kelas dan paket dan kemudian saya mengetik di empat atribut kelas. Dari sana, saya hanya menggunakan mekanisme "Sisipkan Kode" dari NetBeans untuk memasukkan metode pengakses "get" bersama dengan metode toString (), hashCode (), dan sama (Object) yang diganti. Jika saya tidak berpikir saya membutuhkannya, saya dapat membuat kelas lebih sederhana, tetapi sangat mudah untuk membuatnya apa adanya. Sekarang, saya memiliki tipe pengembalian yang jauh lebih dapat digunakan dan ini tercermin dari kode yang menggunakan kelas. Tidak membutuhkan komentar Javadoc sebanyak itu pada tipe kembalian karena tipe tersebut berbicara untuk dirinya sendiri dan mengiklankan isinya dengan metode "get".Saya merasa bahwa sedikit upaya tambahan untuk membuat kelas sederhana ini untuk mengembalikan beberapa nilai terbayar dengan dividen besar jika dibandingkan dengan alternatif seperti mengembalikan status melalui parameter metode atau menggunakan struktur data pengembalian yang lebih umum dan lebih sulit.

Tidaklah terlalu mengherankan bahwa tipe kustom untuk menampung beberapa nilai untuk dikembalikan ke pemanggil adalah solusi yang menarik. Bagaimanapun, ini secara konseptual sangat mirip dengan konsep yang saya tulis di blog sebelumnya terkait dengan penggunaan jenis khusus dan objek parameter untuk meneruskan beberapa parameter terkait daripada meneruskan semuanya secara individual. Java adalah bahasa berorientasi objek dan sangat mengejutkan saya ketika saya tidak melihat objek lebih sering digunakan dalam kode Java untuk mengatur parameter DAN mengembalikan nilai dalam paket yang bagus.

Manfaat dan Keuntungan

Keuntungan menggunakan objek parameter khusus untuk mewakili dan merangkum beberapa nilai kembalian sudah jelas. Parameter metode dapat tetap menjadi parameter "masukan" karena semua informasi keluaran (kecuali untuk informasi kesalahan yang dikomunikasikan melalui mekanisme pengecualian) dapat disediakan dalam objek khusus yang dikembalikan oleh metode. Ini adalah pendekatan yang lebih bersih daripada menggunakan array generik, koleksi, peta, tuple, atau struktur data umum lainnya karena semua pendekatan alternatif tersebut mengalihkan upaya pengembangan ke semua klien potensial.

Biaya dan Kerugian

Saya melihat sedikit kerugian untuk menulis tipe kustom dengan beberapa nilai untuk digunakan sebagai tipe kembalian dari metode Java. Mungkin biaya yang paling sering diklaim adalah harga penulisan dan pengujian kelas-kelas ini, tetapi biaya itu cukup kecil karena kelas-kelas ini cenderung sederhana dan karena IDE modern melakukan sebagian besar pekerjaan untuk kita. Karena IDE melakukannya secara otomatis, kodenya biasanya benar. Kelas-kelas ini sangat sederhana sehingga mudah dibaca oleh peninjau kode dan mudah untuk diuji.