Mengapa Java tidak menggunakan enkapsulasi dengan beberapa kelas?

25

Pertanyaan saya terkait dengan System.indan System.outkelas (mungkin ada orang lain seperti yang ada di perpustakaan Standar). Mengapa demikian? Bukankah itu praktik buruk di OOP? Bukankah seharusnya digunakan seperti: System.getIn()dan System.getOut()? Saya selalu memiliki pertanyaan ini dan saya harap saya dapat menemukan jawaban yang bagus di sini.

Clawdidr
sumber

Jawaban:

36

Definisi untuk indan outbidang dalam Systemkelas adalah:

public final static PrintStream out;
public final static InputStream in;

Ini adalah konstanta. Mereka kebetulan juga objek, tetapi mereka adalah konstanta. Ini sangat mirip dengan kelas Matematika:

public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;

Atau di kelas Boolean:

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

Atau di kelas Warna:

public final static Color white     = new Color(255, 255, 255);
public final static Color black     = new Color(0, 0, 0);
public final static Color red       = new Color(255, 0, 0);

Ketika mengakses konstanta publik yang tidak berubah, tidak ada keuntungan signifikan untuk merangkumnya - secara konseptual atau berbasis kinerja. Itu disana. Itu tidak akan berubah.

Tidak ada perbedaan nyata antara Color.whitedan System.out.


sumber
Yah, saya belum melihatnya seperti itu, mereka adalah benda konstan. Itu penjelasan yang cukup bagus.
Clawdidr
1
@Clawdidr di Java hari ini, orang mungkin mempertimbangkan untuk menggunakan enumuntuk menahan mereka ... meskipun enumbaru dengan Java 1.5 (bukan pilihan dalam 1.0 hari).
Hanya ingin tahu (bukan pengembang Java sendiri): apakah ada perbedaan antara final staticdan static final? Jika demikian, apakah itu?
Marjan Venema
1
@MarjanVenema tidak ada perbedaan, hanya urutan pengubah disukai. checkstyle modifier check menunjukkan urutan yang diinginkan. Rupanya, siapa pun yang menulis dua file sumber dalam versi jdk saya belum menyetujui pesanan. Itu hanya konvensi.
:) dan terima kasih Michael, untuk meluangkan waktu untuk merespons dan untuk tautannya.
Marjan Venema
5

Alasan sebenarnya adalah bahwa ini adalah masalah warisan. The System.in,out,errkonstanta adalah bagian dari Java 1.0 ... dan mungkin banyak kembali lebih lanjut. Pada saat itu jelas bahwa desain punya masalah, sudah terlambat untuk memperbaikinya. Yang terbaik yang bisa mereka lakukan adalah menambahkan System.setIn,setOut,setErrmetode di Java 1.1 dan kemudian menangani masalah spesifikasi bahasa 1 .

Ini mirip dengan masalah mengapa ada System.arraycopymetode statis yang namanya melanggar konvensi penamaan Java.


Seperti apakah ini "desain buruk" atau tidak, saya pikir itu. Ada situasi di mana penanganan non-OO saat ini merupakan masalah serius. (Pikirkan ... bagaimana Anda dapat menjalankan satu program Java di dalam yang lain ketika persyaratan aliran "IO" standarnya bertentangan. Pikirkan ... unit kode pengujian yang mengharuskan Anda mengubah aliran.)

Namun, saya juga dapat mengaitkan dengan argumen bahwa cara melakukan hal-hal saat ini lebih nyaman dalam banyak kasus.


1 - Sangat menarik untuk dicatat bahwa System.in,out,errvariabel mendapatkan perhatian khusus di JLS sebagai memiliki "semantik khusus". JLS mengatakan bahwa jika Anda mengubah nilai finalbidang, perilaku tidak terdefinisi ... kecuali dalam kasus bidang ini .

Stephen C
sumber
2

Saya percaya objek keluar tidak dapat diubah, yang membuatnya entah bagaimana aman (ini bisa diperdebatkan) karena disimpan di bidang statis final publik.

Banyak kelas di JDK tidak menghormati prinsip-prinsip desain berorientasi objek terbaik. Salah satu alasan untuk ini adalah kenyataan bahwa mereka ditulis hampir 20 tahun yang lalu, ketika Object-Orientation hanya muncul sebagai paradigma mainstream dan banyak programmer tidak terbiasa dengan mereka seperti sekarang. Contoh desain API yang buruk adalah API Tanggal & Waktu, yang membutuhkan waktu 19 tahun untuk mengubah ...

m3th0dman
sumber
3
Saya akan membuat pernyataan itu lebih kuat, variabel final publik (statis atau tidak) sama persis dengan "Aman" sebagai pengambil dan saya akan mengalihkan ketidakmampuan pada pasangan setter / pengambil. Setter hampir selalu merupakan ide yang buruk (Immutable adalah baik - dan jika itu tidak dapat berubah metode yang "Set" itu mungkin layak sedikit logika bisnis juga), Jika Anda memerlukan rajin Anda mungkin juga membuatnya publik final, tetapi melakukan keduanya tidak disukai - jangan meminta kelas untuk datanya, minta kelas untuk melakukan sesuatu terhadap data itu.
Bill K
@ BillK: Ya, juga dikenal sebagai Hukum Demeter (meskipun itu bukan hukum, melainkan pedoman).
sleske
2

Jawaban ini bagus dan benar.

Saya ingin menambahkan bahwa dalam beberapa kasus kompromi dilakukan demi kegunaan.

Objek tipe String dapat dipakai tanpa kejadian baru, saat String bukan primitif:

String s = "Hello";

String menjadi non-primitif, harus dipakai seperti ini:

String s = new String("Hello");          // this also works 

Tetapi kompiler memungkinkan untuk opsi yang lebih pendek, lebih sedikit OO, karena String sejauh ini adalah kelas yang paling banyak digunakan di API.

Array juga dapat diinisialisasi dengan cara non-OO:

int i[] = {1,2,3};

Cukup aneh, objek adalah turunan dari kelas atau array . Array makna adalah jenis kelas yang benar-benar terpisah.

Array memiliki lengthbidang publik yang tidak konstan. Juga tidak ada dokumentasi pada array kelas adalah turunan dari. (jangan bingung dengan kelas Array atau java.reflect.Array).

int a = myArray.length;    // not length()
Tulains Córdova
sumber
6
Engkau adalah hal yang berbeda - new String("Hello")akan selalu membuat objek String baru. Sementara String s = "Hello";akan menggunakan objek yang diinternir. Bandingkan: "Hello" == "Hello"mungkin benar, sementara new String("Hello") == new String("Hello")selalu salah. Ada kompilasi waktu optimasi sulap terjadi di pertama yang tidak mungkin dengan new String("Hello"). Lihat en.wikipedia.org/wiki/String_interning
@MichaelT Saya menambahkan beberapa keanehan ekstra pada array, hanya demi kelengkapan.
Tulains Córdova
2
@Tarik Saya keberatan dengan "String menjadi non-primitif, harus di-instanciated seperti ini: String s = new String("Hello");" yang tidak benar. Opsi yang lebih pendek ( String s = "Hello";) lebih tepat karena string interning.
2
Dengan String, tidak ada opsi "lebih benar". Keduanya benar. Meskipun, seperti dikatakan MichaelT, yang lebih pendek lebih disukai karena String magang.
Andres F.
1
@AndresF. Saya mengubah "kurang benar" untuk "kurang OO".
Tulains Córdova