Apakah ini sepenuhnya bertentangan dengan cara Java untuk membuat objek struct seperti?
class SomeData1 {
public int x;
public int y;
}
Saya bisa melihat kelas dengan accessors dan mutators lebih seperti Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
Kelas dari contoh pertama adalah notasional nyaman.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Ini tidak nyaman.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Jawaban:
Ini adalah topik yang sering dibahas. Kerugian membuat bidang publik di objek adalah bahwa Anda tidak memiliki kendali atas nilai yang ditetapkan untuk itu. Dalam proyek grup di mana ada banyak programmer menggunakan kode yang sama, penting untuk menghindari efek samping. Selain itu, kadang-kadang lebih baik mengembalikan salinan objek bidang atau mengubahnya entah bagaimana, dll. Anda dapat mengejek metode tersebut dalam pengujian Anda. Jika Anda membuat kelas baru, Anda mungkin tidak melihat semua tindakan yang mungkin. Ini seperti pemrograman defensif - suatu hari nanti pengambil dan setter mungkin membantu, dan tidak perlu banyak biaya untuk membuat / menggunakannya. Jadi mereka kadang berguna.
Dalam praktiknya, sebagian besar bidang memiliki getter dan setter sederhana. Solusi yang mungkin akan terlihat seperti ini:
Pembaruan: Sangat tidak mungkin bahwa dukungan properti akan ditambahkan di Java 7 atau mungkin sebelumnya. Bahasa JVM lainnya seperti Groovy, Scala, dll mendukung fitur ini sekarang. - Alex Miller
sumber
=
, yang menurut saya membuat kode lebih bersih.x
s yang merupakan dua hal yang berbeda, tidak membuatnya menjadi ide yang baik. IMHO, itu adalah saran yang buruk, karena dapat menyebabkan kebingungan oleh pembaca manusia. Prinsip dasar: jangan membuat pembaca melakukan pengambilan ganda; jelaskan apa yang Anda katakan - Gunakan nama yang berbeda untuk entitas yang berbeda. Bahkan jika perbedaannya hanya untuk menambahkan garis bawah. Jangan mengandalkan tanda baca di sekitarnya untuk membedakan entitas.Tampaknya banyak orang Jawa tidak terbiasa dengan Pedoman Java Java Coding yang mengatakan itu cukup tepat untuk menggunakan variabel instance publik ketika kelas pada dasarnya adalah "Struct", jika Java mendukung "struct" (ketika tidak ada perilaku).
Orang-orang cenderung berpikir getter dan setters adalah cara Jawa, seolah-olah mereka berada di jantung Jawa. Ini tidak benar. Jika Anda mengikuti Pedoman Java Java Coding, menggunakan variabel instance publik dalam situasi yang sesuai, Anda sebenarnya menulis kode yang lebih baik daripada mengacaukannya dengan getter dan setter yang tidak perlu.
Konvensi Kode Java dari tahun 1999 dan masih tidak berubah.
10.1 Memberikan Akses ke Instance dan Variabel Kelas
Jangan membuat instance atau variabel kelas publik tanpa alasan yang jelas. Seringkali, variabel instan tidak perlu secara eksplisit diatur atau didapat-sering yang terjadi sebagai efek samping dari pemanggilan metode.
Salah satu contoh variabel instance publik yang sesuai adalah kasus di mana kelas pada dasarnya adalah struktur data, tanpa perilaku. Dengan kata lain, jika Anda akan menggunakan struct bukan kelas (jika Java mendukung struct), maka itu tepat untuk membuat variabel instance kelas publik .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
sumber
Gunakan akal sehat sebenarnya. Jika Anda memiliki sesuatu seperti:
Lalu ada gunanya membungkus mereka dalam getter dan setter. Anda tidak akan pernah menyimpan koordinat x, y dalam seluruh piksel dengan cara lain. Getters dan setters hanya akan memperlambat Anda.
Di sisi lain, dengan:
Anda mungkin ingin mengubah cara keseimbangan dihitung di beberapa titik di masa depan. Ini harus benar-benar menggunakan getter dan setter.
Selalu lebih baik untuk mengetahui mengapa Anda menerapkan praktik yang baik, sehingga Anda tahu kapan boleh melanggar aturan.
sumber
(-5, -5)
tidak mungkin sebuah ide bagus. :-)Untuk mengatasi masalah mutabilitas, Anda dapat mendeklarasikan x dan y sebagai final. Sebagai contoh:
Kode panggilan yang mencoba menulis ke bidang ini akan mendapatkan kesalahan waktu kompilasi "bidang x dinyatakan final; tidak dapat ditetapkan".
Kode klien kemudian dapat memiliki kenyamanan 'tangan pendek' yang Anda gambarkan dalam posting Anda
sumber
case
ekspresi yang merujuk pada bidang instance tersebut, saya dapatCase expressions must be constant expressions
. apa jalannya ini? apa konsep idiomatik di sini?Jangan gunakan
public
bidangJangan gunakan
public
bidang ketika Anda benar-benar ingin membungkus perilaku internal kelas. Ambiljava.io.BufferedReader
contoh. Ini memiliki bidang berikut:skipLF
dibaca dan ditulis dalam semua metode baca. Bagaimana jika kelas eksternal yang berjalan di utas terpisah secara jahat mengubah keadaanskipLF
di tengah pembacaan?BufferedReader
pasti akan rusak.Gunakan
public
bidangAmbil
Point
kelas ini misalnya:Ini akan membuat menghitung jarak antara dua poin sangat menyakitkan untuk ditulis.
Kelas tidak memiliki perilaku selain pengambil dan setter polos. Dapat diterima untuk menggunakan bidang publik ketika kelas hanya mewakili struktur data, dan tidak memiliki, dan tidak akan pernah memiliki perilaku (getter dan setter yang tipis tidak dianggap sebagai perilaku di sini). Dapat ditulis lebih baik dengan cara ini:
Bersih!
Tapi ingat: Tidak hanya kelas Anda harus absen dari perilaku, tetapi juga harus memiliki tidak alasan untuk memiliki perilaku di masa depan juga.
(Inilah yang dijelaskan jawaban ini . Mengutip "Konvensi Kode untuk Bahasa Pemrograman Java: 10. Praktek Pemrograman" :
Jadi dokumentasi resmi juga menerima praktik ini.)
Selain itu, jika Anda lebih yakin bahwa anggota
Point
kelas di atas tidak dapat diubah, maka Anda dapat menambahkanfinal
kata kunci untuk menegakkannya:sumber
By the way, struktur yang Anda berikan sebagai contoh sudah ada di perpustakaan kelas dasar Java sebagai
java.awt.Point
. Ini memiliki x dan y sebagai bidang publik, periksa sendiri .Jika Anda tahu apa yang Anda lakukan, dan orang lain di tim Anda mengetahuinya, maka boleh saja memiliki bidang publik. Tetapi Anda tidak harus bergantung pada itu karena mereka dapat menyebabkan sakit kepala seperti pada bug yang berhubungan dengan pengembang menggunakan objek seolah-olah mereka stack struct yang dialokasikan (objek java selalu dikirim ke metode sebagai referensi dan bukan sebagai salinan).
sumber
public final
bidang, seperti dalam jawaban Brian, atau dengan memiliki pengambil publik, tetapi tidak ada setter publik. Yaitu, apakah seseorang menggunakan bidang atau aksesor tidak penting.Re: aku, izb, John Topley ...
Waspadai masalah mutabilitas ...
Tampaknya masuk akal untuk menghilangkan getter / setter. Sebenarnya mungkin ok dalam beberapa kasus. Masalah sebenarnya dengan pola yang diusulkan ditunjukkan di sini adalah mutabilitas.
Masalahnya adalah sekali Anda membagikan referensi objek yang berisi bidang publik non-final. Hal lain dengan referensi itu bebas untuk memodifikasi bidang-bidang itu. Anda tidak lagi memiliki kendali atas keadaan objek itu. (Pikirkan apa yang akan terjadi jika String bisa berubah.)
Itu menjadi buruk ketika objek itu merupakan bagian penting dari keadaan internal orang lain, Anda baru saja mengekspos implementasi internal. Untuk mencegah ini, salinan objek harus dikembalikan sebagai gantinya. Ini berfungsi, tetapi dapat menyebabkan tekanan GC besar-besaran dari banyak salinan sekali pakai yang dibuat.
Jika Anda memiliki bidang publik, pertimbangkan untuk membuat kelas hanya-baca. Tambahkan bidang sebagai parameter ke konstruktor, dan tandai bidang terakhir. Kalau tidak, pastikan Anda tidak mengekspos keadaan internal, dan jika Anda perlu membuat instance baru untuk nilai pengembalian, pastikan itu tidak akan dipanggil berlebihan.
Lihat: " Java Efektif " oleh Joshua Bloch - Item # 13: Favor Immutability.
PS: Juga perlu diingat, semua JVM hari ini akan mengoptimalkan getMethod jika mungkin, menghasilkan hanya satu instruksi lapangan-baca.
sumber
Saya telah mencoba ini dalam beberapa proyek, pada teori yang getter dan setter mengacaukan kode dengan cruft semantik tidak bermakna, dan bahwa bahasa lain tampaknya baik-baik saja dengan penyembunyian data berbasis partisi atau pembagian tanggung jawab (misalnya python).
Seperti yang orang lain catat di atas, ada 2 masalah yang Anda hadapi, dan mereka tidak benar-benar diperbaiki:
Dan ini adalah skenario kasus terbaik untuk bekerja sepenuhnya dalam proyek pribadi mandiri. Setelah Anda mengekspor semuanya ke perpustakaan yang dapat diakses publik, masalah ini akan menjadi lebih besar.
Java sangat verbose, dan ini adalah hal yang menggoda untuk dilakukan. Jangan lakukan itu.
sumber
Jika cara Java adalah cara OO, maka ya, membuat kelas dengan bidang publik mematahkan prinsip-prinsip seputar penyembunyian informasi yang mengatakan bahwa objek harus mengelola keadaan internalnya sendiri. (Jadi karena saya tidak hanya mengutarakan jargon kepada Anda, manfaat dari menyembunyikan informasi adalah bahwa cara kerja internal suatu kelas tersembunyi di balik antarmuka - katakan Anda ingin mengubah mekanisme yang digunakan oleh kelas struct Anda untuk menyimpan salah satu bidangnya, Anda mungkin harus kembali dan mengubah kelas yang menggunakan kelas ...)
Anda juga tidak dapat memanfaatkan dukungan untuk kelas yang memenuhi persyaratan penamaan JavaBean, yang akan merugikan jika Anda memutuskan untuk, katakanlah, menggunakan kelas dalam Halaman JavaServer yang ditulis menggunakan Bahasa Ekspresi.
Artikel JavaWorld Mengapa Metode Getter dan Setter adalah artikel Jahat juga mungkin menarik bagi Anda untuk memikirkan kapan tidak menerapkan metode accessor dan mutator.
Jika Anda menulis solusi kecil dan ingin meminimalkan jumlah kode yang terlibat, cara Java mungkin bukan cara yang benar - saya kira itu selalu tergantung pada Anda dan masalah yang Anda coba pecahkan.
sumber
Tidak ada yang salah dengan jenis kode itu, asalkan penulis tahu itu adalah struct (atau data shuttles) alih-alih objek. Banyak pengembang Java tidak dapat membedakan antara objek yang terbentuk dengan baik (bukan hanya subclass dari java.lang.Object, tetapi objek sebenarnya dalam domain tertentu) dan nanas. Ergo, mereka akhirnya menulis struct ketika mereka membutuhkan objek dan sebaliknya.
sumber
Masalah dengan menggunakan akses bidang publik adalah masalah yang sama seperti menggunakan yang baru alih-alih metode pabrik - jika Anda berubah pikiran nanti, semua penelepon yang ada rusak. Jadi, dari sudut pandang evolusi API, biasanya ide yang baik untuk menggigit peluru dan menggunakan getter / setter.
Satu tempat di mana saya pergi dengan cara lain adalah ketika Anda sangat mengontrol akses ke kelas, misalnya dalam kelas statis dalam yang digunakan sebagai struktur data internal. Dalam hal ini, mungkin jauh lebih jelas untuk menggunakan akses bidang.
Omong-omong, pada pernyataan e-bartek, sangat tidak mungkin IMO bahwa dukungan properti akan ditambahkan di Jawa 7.
sumber
Saya sering menggunakan pola ini ketika membangun kelas dalam pribadi untuk menyederhanakan kode saya, tetapi saya tidak akan merekomendasikan mengekspos objek seperti itu di API publik. Secara umum, semakin sering Anda dapat membuat objek di API publik Anda menjadi lebih baik, dan tidak mungkin untuk membuat objek 'mirip-bangunan' Anda dengan cara yang tidak dapat diubah.
Sebagai tambahan, bahkan jika saya menulis objek ini sebagai kelas dalam pribadi saya masih akan menyediakan konstruktor untuk menyederhanakan kode untuk menginisialisasi objek. Harus memiliki 3 baris kode untuk mendapatkan objek yang dapat digunakan ketika seseorang akan melakukannya berantakan.
sumber
Sebuah pertanyaan yang sangat-sangat lama, tetapi izinkan saya memberikan kontribusi singkat lainnya. Java 8 memperkenalkan ekspresi lambda dan referensi metode. Ekspresi Lambda dapat menjadi referensi metode sederhana dan tidak mendeklarasikan tubuh "benar". Tetapi Anda tidak dapat "mengubah" bidang menjadi referensi metode. Jadi
tidak legal, tapi
adalah.
sumber
data -> data.x
, yang masih masuk akalSaya tidak melihat ada salahnya jika Anda tahu bahwa itu akan selalu menjadi struct sederhana dan bahwa Anda tidak akan pernah ingin melampirkan perilaku itu.
sumber
Ini adalah pertanyaan tentang Desain Berorientasi Objek, bukan bahasa Jawa. Ini adalah praktik yang baik untuk menyembunyikan tipe data di dalam kelas dan hanya mengekspos metode yang merupakan bagian dari API kelas. Jika Anda mengekspos tipe data internal, Anda tidak akan pernah bisa mengubahnya di masa mendatang. Jika Anda menyembunyikannya, satu-satunya kewajiban Anda kepada pengguna adalah metode pengembalian dan tipe argumen.
sumber
Di sini saya membuat program untuk memasukkan Nama dan Usia 5 orang yang berbeda dan melakukan semacam pemilihan (berdasarkan usia). Saya menggunakan kelas yang bertindak sebagai struktur (seperti bahasa pemrograman C) dan kelas utama untuk melakukan operasi lengkap. Di bawah ini saya memberikan kode ...
Kode di atas adalah Bebas Kesalahan dan Diuji ... Cukup salin dan tempel ke IDE Anda dan ... Anda tahu dan apa ??? :)
sumber
Anda dapat membuat kelas sederhana dengan bidang publik dan tanpa metode di Jawa, tetapi masih merupakan kelas dan masih ditangani secara sintaksis dan dalam hal alokasi memori seperti kelas. Tidak ada cara untuk benar-benar mereproduksi struct di Jawa.
sumber
Kadang saya menggunakan kelas seperti itu, ketika saya harus mengembalikan beberapa nilai dari suatu metode. Tentu saja, objek tersebut berumur pendek dan dengan visibilitas yang sangat terbatas, jadi itu harus OK.
sumber
Seperti kebanyakan hal, ada aturan umum dan kemudian ada keadaan khusus. Jika Anda melakukan aplikasi tertutup, ditangkap sehingga Anda tahu bagaimana objek yang diberikan akan digunakan, maka Anda dapat menggunakan lebih banyak kebebasan untuk mendukung visibilitas dan / atau efisiensi. Jika Anda mengembangkan kelas yang akan digunakan secara publik oleh orang lain di luar kendali Anda, maka condongkan diri ke model pengambil / penyetel. Seperti halnya semua hal, gunakan akal sehat saja. Sering oke untuk melakukan putaran awal dengan publik dan kemudian mengubahnya untuk pengambil / setter nanti.
sumber
Pemrograman berorientasi aspek memungkinkan Anda menjebak tugas atau mengambil dan melampirkan intersepsi logika kepada mereka, yang saya usulkan adalah cara yang tepat untuk menyelesaikan masalah. (Masalah apakah mereka harus publik atau dilindungi atau dilindungi paket adalah ortogonal.)
Dengan demikian Anda mulai dengan bidang yang tidak disintesis dengan kualifikasi akses yang tepat. Ketika persyaratan program Anda bertambah, Anda melampirkan logika untuk memvalidasi, membuat salinan objek yang dikembalikan, dll.
Filosofi pengambil / penyetel membebankan biaya pada sejumlah besar kasus sederhana di mana mereka tidak diperlukan.
Apakah aspek-gaya lebih bersih atau tidak agak kualitatif. Saya akan merasa mudah untuk melihat hanya variabel di kelas dan melihat logikanya secara terpisah. Kenyataannya, raison d'etre untuk pemrograman berorientasi-Apect adalah bahwa banyak masalah lintas sektoral dan pengelompokannya ke dalam tubuh kelas itu sendiri tidak ideal (mencatat sebagai contoh - jika Anda ingin log semua dapatkan Java ingin Anda menulis sejumlah getter dan menjaganya agar tetap sinkron tetapi AspectJ memungkinkan Anda membuat satu kalimat).
Masalah IDE adalah herring merah. Ini bukan pengetikan seperti pembacaan dan polusi visual yang muncul dari get / set.
Anotasi tampak mirip dengan pemrograman berorientasi aspek pada pandangan pertama namun mereka mengharuskan Anda untuk menghitung secara rinci pointcuts dengan melampirkan anotasi, sebagai lawan dari spesifikasi pointcut mirip kartu liar seperti di AspectJ.
Saya harap kesadaran akan AspectJ mencegah orang dari terlalu dini untuk menentukan bahasa yang dinamis.
sumber