Struct like objects di Java

195

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();
}
Chris de Vries
sumber
9
Alih-alih bidang yang bisa berubah publik, pertimbangkan bidang yang tidak bisa berubah untuk publik atau bidang yang bisa berubah paket-lokal. Entah akan lebih baik IMHO.
Peter Lawrey
Ingat bahwa, sementara getter dan setter jelek / bertele-tele, itu semacam hati Jawa. Ini adalah bahasa yang tidak ringkas. Di sisi lain, Anda harus TIDAK PERNAH mengetik semua itu, karena itulah yang IDE Anda lakukan untuk Anda. Dalam bahasa dinamis Anda harus mengetik lebih sedikit, tetapi Anda harus mengetik (umumnya, meskipun IDE dapat membantu).
Dan Rosenstark
Ironisnya, sementara OO memiliki kekuatan dalam hal enkapsulasi, ini ada harga yang harus dibayar CPU dan penyimpanan bijaksana. Pengumpul Sampah (hampir sepenuhnya) menghilangkan keharusan mengkhawatirkan kapan referensi objek harus dihapus. Tren saat ini akan berputar penuh dengan menggunakan struct C-like off-heap. Ini sempurna untuk solusi tipe caching, komunikasi antar proses, operasi intensif-memori yang lebih cepat, GC o / jam yang lebih rendah dan bahkan dapat mengambil manfaat dari o penyimpanan yang lebih rendah untuk set data Anda. Jika Anda tahu apa yang Anda lakukan, Anda tidak akan menanyakan pertanyaan ini ... jadi pikirkan lagi!
user924272
@ user924272: Re "Tren saat ini akan menjadi lingkaran penuh dengan menggunakan struct C-like off-heap". Yang akan Anda lakukan di Jawa bagaimana ??? IMHO, ini adalah area di mana Java menunjukkan umurnya ...
ToolmakerSteve
@ToolmakerSteve -Aku melihat lingkaran. Saya bukan satu satunya. Perusahaan seperti Azul panas pada pengumpulan sampah tanpa jeda. Jawa sudah tua. Benar. Insinyur yang melihat kelemahan dan melakukan sesuatu tentang itu, bukan mengeluh? Mereka layak dihormati! +10 untuk Azul dari saya :-)
user924272

Jawaban:

62

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:

public property String foo;   
a->Foo = b->Foo;

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

Bartosz Bierkowski
sumber
28
Sayang sekali, saya suka properti bergaya C # (yang terdengar seperti apa yang Anda bicarakan)
Jon Onstott
2
Jadi gunakan overloading ... private int _x; kekosongan publik x (nilai int) {_x = nilai; } public int x () {return _x; }
Gordon
12
Saya lebih suka bisa menggunakan =, yang menurut saya membuat kode lebih bersih.
Svish
6
@ T-Bull: Hanya karena Anda BISA memiliki dua xs 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.
ToolmakerSteve
2
@ToolmakerSteve: Bahwa "dapat menyebabkan kebingungan" adalah argumen yang paling umum dan masih terlemah ketika datang untuk membela dogma pengkodean (sebagai lawan dari gaya pengkodean). Selalu ada seseorang yang BISA bingung dengan hal-hal sederhana. Anda akan selalu menemukan seseorang yang mengeluh bahwa dia melakukan kesalahan setelah tetap terjaga dan menulis kode selama setengah minggu atau lebih dan kemudian menyalahkan gaya pengkodean yang menyesatkan. Saya tidak membiarkan hal itu diperhitungkan. Gaya itu valid, jelas dan menjaga namespace tetap bersih. Juga, tidak ada entitas yang berbeda di sini, ada / satu / entitas dan beberapa kode boilerplate di sekitarnya.
T-Bull
290

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

developer.g
sumber
88
+1 Untuk benar-benar memiliki sumber yang berwenang. Setiap jawaban lain adalah orang-orang memutar opini mereka seolah-olah itu fakta.
ArtOfWarfare
1
Ada spesifikasi Java Beans yang merupakan cara standar industri untuk mengakses properti menggunakan metode get and set ... lihat en.wikipedia.org/wiki/JavaBeans untuk ikhtisar.
user924272
4
@ user924272: Bagaimana spesifikasi Java Beans relevan dengan jawaban ini, yang membahas kapan saat yang tepat untuk menggunakan "variabel instance publik"? Jika spec adalah cara standar untuk secara otomatis mengubah variabel instan menjadi properti, ala C #, itu mungkin relevan. Tapi ternyata tidak, kan? Ini hanya menentukan penamaan getter dan setter boilerplate yang perlu dibuat, untuk membuat pemetaan seperti itu.
ToolmakerSteve
@ToolmakerSteve. Ini pertanyaan java. Selain itu, pertanyaan itu menghindarkan dari masalah umum di mana spesifikasi ada. Dari perspektif old-school, jauh lebih mudah untuk men-debug mutasi bidang ketika ada cara standar untuk melakukannya - atur breakpoint pada setter. Ini mungkin telah dibuat usang dengan debuggers modern, namun saya terpaksa mengerutkan dahi pada kelas yang secara langsung "meninju" objek ... sementara ini tidak masalah untuk aplikasi yang lebih kecil, itu adalah sakit kepala nyata untuk aplikasi yang lebih besar dan organisasi besar
user924272
223

Gunakan akal sehat sebenarnya. Jika Anda memiliki sesuatu seperti:

public class ScreenCoord2D{
    public int x;
    public int y;
}

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:

public class BankAccount{
    public int balance;
}

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.

izb
sumber
3
Saya setuju dengan jawaban ini dan mengatakan lebih lanjut bahwa Anda dapat membuat kelas dengan bidang publik asalkan bidangnya berani independen satu sama lain. yaitu satu bidang tidak bergantung pada bidang lainnya. Ini bisa sangat berguna dalam banyak kasus, untuk beberapa nilai pengembalian dari suatu fungsi, atau untuk co-odinates kutub. {angle, length} yang berjalan bersama tetapi tidak saling bergantung dengan cara intrinsik apa pun.
Spacen Jasset
@SpacenJasset: FYI, saya tidak melihat bagaimana contoh Anda (beberapa nilai balik; koordinat kutub) ada hubungannya dengan apakah menggunakan bidang publik vs pengambil / setter. Dalam hal nilai balik berganda, bahkan mungkin kontraproduktif, karena bisa dibilang penelepon seharusnya hanya MENDAPATKAN nilai yang dikembalikan, yang berargumen mendukung getter publik dan setter swasta (tidak berubah). Ini mungkin juga berlaku untuk mengembalikan koordinat kutub dari objek (x, y) - pertimbangkan kesalahan matematika AKUMULATIF, karena perubahan pada masing-masing komponen koordinat kutub dikonversi kembali ke (x, y).
ToolmakerSteve
@SpacenJasset: Tapi saya setuju dengan prinsip Anda.
ToolmakerSteve
1
Anda memiliki poin yang valid, tetapi saya merasa bahwa piksel adalah contoh yang buruk karena memastikan piksel ada di dalam jendela (hanya sebuah contoh) adalah sesuatu yang mungkin dilakukan seseorang, dan selain itu, membiarkan seseorang mengatur piksel (-5, -5)tidak mungkin sebuah ide bagus. :-)
Horsey
50

Untuk mengatasi masalah mutabilitas, Anda dapat mendeklarasikan x dan y sebagai final. Sebagai contoh:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

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

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
Brian
sumber
3
Terima kasih - jawaban yang berguna dan ringkas. Memperlihatkan cara mendapatkan manfaat sintaksis bidang, saat tidak ingin mutabilitas.
ToolmakerSteve
@ToolmakerSteve - terima kasih atas umpan baliknya - sangat kami hargai.
Brian
Saya mencoba menggunakan instance akhir dari kelas akhir dengan bidang akhir sebagai struct "instance", tetapi dalam caseekspresi yang merujuk pada bidang instance tersebut, saya dapat Case expressions must be constant expressions. apa jalannya ini? apa konsep idiomatik di sini?
n611x007
1
bidang terakhir masih referensi ke objek, yang bukan konstanta, karena akan diinisialisasi saat kelas pertama kali digunakan. Kompiler tidak dapat mengetahui "nilai" dari referensi objek. Konstanta harus diketahui saat menyusun.
Johan Tidén
1
+1 Jawaban yang sangat penting. Kegunaan kelas yang tidak dapat diubah tidak dapat diremehkan menurut pendapat saya. Semantik "api-dan-lupakan" mereka membuat alasan tentang kode seringkali lebih sederhana, terutama di lingkungan multithreaded, di mana mereka dapat dibagi secara sewenang-wenang di antara utas, tanpa sinkronisasi.
TheOperator
11

Jangan gunakan publicbidang

Jangan gunakan publicbidang ketika Anda benar-benar ingin membungkus perilaku internal kelas. Ambil java.io.BufferedReadercontoh. Ini memiliki bidang berikut:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLFdibaca dan ditulis dalam semua metode baca. Bagaimana jika kelas eksternal yang berjalan di utas terpisah secara jahat mengubah keadaan skipLFdi tengah pembacaan? BufferedReaderpasti akan rusak.

Gunakan publicbidang

Ambil Pointkelas ini misalnya:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

Ini akan membuat menghitung jarak antara dua poin sangat menyakitkan untuk ditulis.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

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:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

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" :

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 structbukan kelas (jika Java didukung struct), maka itu tepat untuk membuat variabel instance kelas publik.

Jadi dokumentasi resmi juga menerima praktik ini.)


Selain itu, jika Anda lebih yakin bahwa anggota Pointkelas di atas tidak dapat diubah, maka Anda dapat menambahkan finalkata kunci untuk menegakkannya:

public final double x;
public final double y;
sampathsris
sumber
8

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).

Spoike
sumber
+1 Disebutkan dengan baik masalah - suatu cara di mana hasilnya masih TIDAK seperti C struct. Namun, masalah yang Anda ajukan tentang objek java selalu dengan referensi, tidak diperbaiki dengan membuat setter alih-alih memiliki bidang yang dapat ditulis publik (yang merupakan inti dari pertanyaan OP - representasi mana yang akan digunakan). Sebaliknya, ini adalah argumen yang mendukung melakukan BAIK. Ini adalah argumen untuk ketidakmampuan. Yang bisa dilakukan sebagai public finalbidang, seperti dalam jawaban Brian, atau dengan memiliki pengambil publik, tetapi tidak ada setter publik. Yaitu, apakah seseorang menggunakan bidang atau aksesor tidak penting.
ToolmakerSteve
8

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.

Mark Renouf
sumber
12
Bagaimana seorang pengambil / penyelesai menyelesaikan masalah ini. Anda masih memiliki referensi, Anda tidak memiliki sinkronisasi dengan operasi. Getters / setters tidak memberikan perlindungan di dalam dan dari diri mereka sendiri.
he_the_great
1
Getters dan setters dapat memberikan sinkronisasi jika diperlukan. Anda juga mengharapkan getter dan setter untuk melakukan lebih dari yang ditentukan untuk dilakukan. Terlepas dari ini, masalah sinkronisasi masih remamins.
user924272
7

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:

  • Hampir semua alat otomatis di dunia java bergantung pada konvensi pengambil / penyetel. Ditto for, seperti yang dicatat oleh orang lain, tag jsp, konfigurasi pegas, alat gerhana, dll. ... Berperang melawan apa yang diharapkan oleh alat Anda adalah resep untuk sesi panjang menelusuri melalui google mencoba menemukan cara memulai standar yang tidak standar kacang musim semi. Benar-benar tidak sepadan dengan masalahnya.
  • Setelah Anda memiliki aplikasi yang dikodekan secara elegan dengan ratusan variabel publik, Anda kemungkinan akan menemukan setidaknya satu situasi di mana mereka tidak mencukupi - di mana Anda benar-benar membutuhkan kekekalan, atau Anda perlu memicu beberapa peristiwa ketika variabel diatur, atau Anda ingin melempar pengecualian pada perubahan variabel karena menetapkan status objek ke sesuatu yang tidak menyenangkan. Anda kemudian terjebak dengan pilihan-pilihan yang tidak diinginkan antara mengacaukan kode Anda dengan beberapa metode khusus di mana pun variabel tersebut direferensikan secara langsung, memiliki beberapa formulir akses khusus untuk 3 dari 1000 variabel dalam aplikasi Anda.

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.

Steve B.
sumber
Diskusi yang sangat baik tentang masalah turun jalan bidang publik. Kelemahan Jawa yang pasti, yang mengganggu saya ketika saya harus kembali ke Jawa dari C # (yang belajar dari ketidaknyamanan Jawa di sini).
ToolmakerSteve
4

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.

brabster
sumber
1
+1 untuk tautan ke artikel "Mengapa Metode Getter dan Setter adalah Jahat". Namun, jawaban Anda akan lebih jelas jika Anda menunjukkan bahwa KEDUA bidang publik DAN pengambil / publik sama sekali BUKAN cara Jawa: Seperti yang dijelaskan dalam artikel itu - jika mungkin, jangan lakukan keduanya. Alih-alih, berikan klien metode yang spesifik untuk apa yang perlu mereka lakukan, daripada mencerminkan representasi internal dari instance. NAMUN, ini tidak benar-benar menjawab pertanyaan yang diajukan (yang digunakan, untuk kasus "struct" sederhana), yang lebih baik dijawab oleh developer.g, izb, dan Brian.
ToolmakerSteve
3

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.

luis.espinal
sumber
nanas membuatku tertawa :)
Guillaume
Namun, jawaban ini tidak mengatakan apa-apa tentang perbedaan itu. Menyeret pada pengembang yang tidak terampil tidak membantu pengembang tahu kapan membuat struct, dan kapan membuat kelas.
ToolmakerSteve
Itu tidak mengatakan apa-apa tentang perbedaan karena mereka penulis menyadari perbedaan (dia tahu apa entitas struct-suka). Penulis bertanya apakah menggunakan struct cocok dalam bahasa OO, dan saya katakan ya (tergantung pada domain masalah.) Jika pertanyaannya adalah tentang apa yang membuat objek menjadi objek domain nyata, maka Anda akan memiliki kaki untuk berdiri di Anda argumen.
luis.espinal
Selain itu, satu-satunya jenis pengembang tidak terampil yang seharusnya tidak tahu bedanya adalah yang masih di sekolah. Ini sangat mendasar, seperti mengetahui perbedaan antara daftar tertaut dan tabel hash. Jika seseorang lulus dengan gelar perangkat lunak 4 tahun tanpa mengetahui apa objek yang sebenarnya, maka orang itu tidak terpotong untuk karier ini, atau ia harus kembali ke sekolah dan meminta pengembalian uang. Aku serius.
luis.espinal
Tetapi untuk memuaskan keluhan Anda, saya akan memberikan jawaban (yang tidak ada hubungannya dengan pertanyaan awal dan yang pantas utas sendiri). Objek memiliki perilaku dan merangkum keadaan. Structs tidak. Objek adalah mesin negara. Structs hanya untuk mengumpulkan data. Jika orang menginginkan jawaban yang lebih rumit, mereka bebas untuk membuat pertanyaan baru di mana kita dapat menguraikannya sesuai dengan isi hati kita.
luis.espinal
2

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.

Alex Miller
sumber
1
Ini benar, tetapi jika Anda menggunakan Java, ini bukan masalah, karena Anda dapat memperbaiki seluruh basis kode dalam satu klik (Eclipse, Netbeans, mungkin VIM dan Emacs juga). Jika Anda memilih salah satu teman dinamisnya, seperti Groovy, bahkan enkapsulasi sederhana dapat Anda perbaiki selama berjam-jam atau berhari-hari. Untungnya Anda akan memiliki kasus pengujian yang akan memberi tahu Anda ... berapa banyak lagi kode yang harus Anda perbaiki.
Dan Rosenstark
2
Anda tentu saja berasumsi bahwa semua pengguna berada di basis kode Anda, tetapi tentu saja, itu sering kali tidak benar. Seringkali bahkan tidak mungkin karena berbagai alasan non-teknis untuk mengubah kode yang mungkin berada di basis kode Anda sendiri.
Alex Miller
2

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.

Kris Nuttycombe
sumber
2

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

stream.mapToInt(SomeData1::x)

tidak legal, tapi

stream.mapToInt(SomeData2::getX)

adalah.

Lyubomyr Shaydariv
sumber
Dalam hal ini Anda dapat menggunakan data -> data.x, yang masih masuk akal
James Kraus
1

Saya tidak melihat ada salahnya jika Anda tahu bahwa itu akan selalu menjadi struct sederhana dan bahwa Anda tidak akan pernah ingin melampirkan perilaku itu.

John Topley
sumber
1

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.

Jonathan
sumber
1

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 ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if(nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

Kode di atas adalah Bebas Kesalahan dan Diuji ... Cukup salin dan tempel ke IDE Anda dan ... Anda tahu dan apa ??? :)

Avik Kumar Goswami
sumber
0

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.

pisau cukur
sumber
0

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.

PhiLho
sumber
0

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.

Evvo
sumber
0

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.

ahli nujum
sumber