Mengapa anggota pribadi dapat diakses dengan metode statis?

25

Berikut ini adalah kode pseudo, saya mencobanya dalam Java dan PHP dan keduanya bekerja:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

Mengapa Anda bisa melakukan ini dalam paradigma OOP dan apa gunanya?

Ben
sumber
6
Kenapa tidak? Di Jawa, anggota pribadi tidak pribadi untuk instance, tetapi lebih pribadi untuk file sumber . Penggunaan pertama yang muncul dalam pikiran adalah equalsbahwa harus memeriksa bidang pribadi dari contoh lain. (Posting sebagai komentar, karena ini singkat, dan tidak ada tentang OOP-ness dari pendekatan ini)
Ordous
2
Perhatikan bahwa metode statis tidak memiliki this, jadi satu-satunya objek dari kelas mereka sendiri yang dapat mereka peroleh adalah yang mereka buat sendiri (atau yang diteruskan sebagai parameter). Jadi, jika Anda menganggap ini sebagai pelanggaran enkapsulasi atau lubang keamanan, ini bukan seolah-olah itu sangat besar, dan mungkin tidak layak dicolokkan.
Kilian Foth
4
Tidak yakin mengapa ini diturunkan. Pertanyaannya mungkin sepele (ish), tetapi OP mengalami kesulitan menguji perilaku dalam dua bahasa sebelum bertanya. Itu jauh lebih banyak upaya daripada yang biasanya kita lihat dari pendatang baru.
yannis
1
@YannisRizos Setuju, dan sebenarnya saya tidak menganggap pertanyaan itu sepele. Ini memiliki implikasi untuk mengikuti "prinsip hak istimewa yang paling rendah". Ini berarti fungsi pembantu yang tidak memerlukan akses ke internal instance harus didefinisikan dalam kelas yang terpisah , dan sebaliknya ketika konvensi ini diikuti, Anda akan tahu bahwa setiap kali ada metode statis dalam kelas yang sama, itu mengakses keadaan internal.
Doval
1
Bahkan, ketika saya bertanya kepada colegues saya, mereka semua mengatakan ini tidak mungkin. Itu sebabnya saya tidak menganggapnya sepele
Ben

Jawaban:

17

Di Jawa, variabel pribadi terlihat oleh seluruh kelas. Mereka dapat diakses dari metode statis dan dari instance lain dari kelas yang sama.

Ini, misalnya, berguna dalam metode pabrik . Metode pabrik biasanya melakukan inisialisasi ke objek yang sangat kompleks sehingga Anda tidak ingin membiarkannya pada kode aplikasi. Untuk melakukan inisialisasi, metode pabrik seringkali memerlukan akses ke internal kelas yang tidak ingin Anda tampilkan. Mampu mengakses variabel pribadi secara langsung membuat hidup Anda jauh lebih mudah.

Namun, ketika Anda ingin menyembunyikan detail implementasi kelas bahkan dari metode statis atau dari contoh lain dari kelas itu, Anda bisa mengikuti pola data kelas privat . Masukkan semua variabel pribadi dari suatu kelas ke dalam kelas dalam pribadi dan delegasikan setiap getter atau setter ke getter dan setter dari kelas dalam itu.

Pilihan lain adalah mendefinisikan antarmuka untuk kelas yang mendeklarasikan semua metode publik kelas dan kemudian hanya merujuk kelas di bawah antarmuka itu jika memungkinkan. Referensi ke tipe antarmuka tidak dapat digunakan untuk secara langsung mengakses apa pun yang tidak dideklarasikan di antarmuka, di mana pun (kecuali dengan refleksi, tentu saja). Ketika Anda menggunakan bahasa pemrograman berorientasi objek yang tidak memiliki antarmuka (seperti C ++, misalnya), mereka dapat disimulasikan dengan kelas dasar abstrak yang diwarisi oleh kelas aktual.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}
Philipp
sumber
Bisakah Anda memikirkan situasi ketika pola data kelas pribadi berguna? Saya pribadi menggunakan kelas dalam hanya di GUI seperti pengaturan (Swing, dll) atau kelas dalam statis dalam latihan pengkodean karena saya tidak ingin latihan untuk span beberapa file sumber.
InformedA
1
Menyembunyikan internal kelas dari instance lain menghilangkan salah satu kelebihan yang dimiliki kelas atas antarmuka tanpa mendapatkan imbalan apa pun. Solusi yang lebih sederhana dan lebih fleksibel adalah dengan menggunakan antarmuka saja.
Doval
3

Beberapa bahasa dan kerangka kerja runtime (mis. Java, .NET) membuat asumsi bahwa siapa pun yang mengkompilasi kode untuk kelas tertentu dapat dipercaya untuk tidak menggunakan anggota pribadi apa pun dari setiap instance dari kelas itu dengan cara yang akan merugikan kebenarannya. operasi. Bahasa dan kerangka kerja lain lebih membatasi dalam hal itu, dan tidak mengizinkan akses ke anggota pribadi dari suatu instance kecuali dengan kode yang berjalan pada instance itu . Kedua desain memiliki kelebihan dan kekurangan.

Keuntungan terbesar dari mengizinkan kode apa pun dalam kelas untuk mengakses anggota pribadi dari setiap contoh adalah bahwa ada kasus-kasus di mana tingkat akses sesuai, dan memiliki privatepekerjaan seperti itu menghilangkan kebutuhan untuk memiliki kualifikasi akses yang berbeda tersedia untuk tujuan itu atau selain itu memaksa kode untuk mengekspos anggota lebih luas daripada yang seharusnya ideal.

Keuntungan dari penolakan akses tersebut (seperti yang terjadi pada Microsoft Common Object Model (COM)) adalah memungkinkan kode luar untuk memperlakukan kelas sebagai antarmuka. Jika suatu kelas ImmutableMatrixberisi double[][]bidang dukungan pribadi atau dilindungi , dan jika kode di dalam kelas memeriksa array dukungan dari instance lain, maka tidak mungkin untuk mendefinisikan kelas yang tidak didukung array (misalnya ZeroMatrix, IdentityMatrix) yang kode luarnya dapat digunakan sebagai sebuah Immutable2dMatrix, tanpa kelas itu harus menyertakan bidang dukungan. Jika tidak ada yang Immutable2dMatrixmenggunakan anggota pribadi dari instance selain itu this, maka akan mungkin untuk mengubah nama kelas menjadi ImmutableArrayBackedMatrix, dan mendefinisikan ImmutableMatrixkelas abstrak baru yang bisa memiliki ImmutableArrayBackedMatrixserta kelas-kelas yang didukung non-array yang didukung sebagai subtipe.

Perhatikan bahwa refactoring seperti itu tidak akan dicegah dengan memiliki bahasa "memungkinkan" ImmutableMatrixuntuk memeriksa array dukungan untuk contoh selain this, kecuali bahasa mengambil keuntungan dari kemampuan itu dan benar-benar memeriksa contoh luar. Efek utama dari memiliki bahasa membatasi penggunaan tersebut adalah bahwa hal itu akan membuat compiler squawk segera pada setiap upaya untuk menulis kode yang tidak akan setuju dengan refactoring tersebut.

supercat
sumber
2

Java bukan semata-mata bahasa berorientasi objek, tetapi bahasa berbasis kelas - kelas menentukan operasi dan akses perilaku daripada instance.

Jadi jangan terlalu terkejut bahwa ini memungkinkan Anda melakukan hal-hal yang tidak sepenuhnya berorientasi objek.

Karena metode ini berada dalam lingkup kelas yang sama dengan instance, metode ini memiliki akses penuh ke anggota pribadi. Aturan serupa mengatur instance kelas dalam mengakses data dari instance kelas luar - instance kelas batin dapat mengakses anggota pribadi dari kelas luar.

Ini diwarisi dari C ++, yang berguna untuk membuat copy dan memindahkan konstruktor. Ini juga berguna untuk membandingkan atau menggabungkan dua objek di mana nilainya tergantung pada anggota yang tidak dapat diakses publik secara efisien (misalnya, pengambil untuk array di Jawa harus menyalin array sehingga kode klien tidak dapat memodifikasinya, mengubah keadaan internal objek, tetapi harus menyalin array untuk membandingkan kesetaraan objek tidak efisien)

Pete Kirkham
sumber