Apakah Anda pernah menggunakan variabel anggota yang dilindungi?

97

Apakah Anda pernah menggunakan variabel anggota yang dilindungi? Apa keuntungannya dan masalah apa yang bisa ditimbulkannya?

John Channing
sumber

Jawaban:

74

Apakah Anda pernah menggunakan variabel anggota yang dilindungi?

Tergantung pada seberapa pilih-pilih Anda tentang keadaan persembunyian.

  • Jika Anda tidak ingin ada kebocoran status internal, maka mendeklarasikan semua variabel anggota Anda sebagai pribadi adalah cara yang harus dilakukan.
  • Jika Anda tidak terlalu peduli bahwa subclass dapat mengakses status internal, maka dilindungi sudah cukup baik.

Jika seorang pengembang datang dan membuat subkelas dari kelas Anda, mereka mungkin mengacaukannya karena mereka tidak memahaminya sepenuhnya. Dengan anggota pribadi, selain antarmuka publik, mereka tidak dapat melihat detail spesifik implementasi tentang bagaimana sesuatu dilakukan yang memberi Anda fleksibilitas untuk mengubahnya nanti.

Allain Lalonde
sumber
1
Dapatkah Anda mengomentari kinerja variabel yang dilindungi vs variabel pribadi dengan metode get / set?
Jake
3
Saya akan mengatakan itu bukan sesuatu yang perlu dikhawatirkan kecuali Anda menemukan melalui profil bahwa leher botol akhirnya menjadi pengakses (yang hampir tidak pernah terjadi). Ada trik yang bisa dilakukan untuk membuat JIT lebih pintar tentang berbagai hal jika akhirnya menjadi masalah. Di java misalnya, Anda dapat mengisyaratkan bahwa pengakses dapat disebariskan dengan menandainya sebagai final. Meskipun sejujurnya, kinerja pengambil dan penyetel jauh lebih penting daripada berurusan dengan organisasi sistem dan dengan masalah kinerja aktual seperti yang ditentukan oleh profiler.
Allain Lalonde
23
@ Jake: Anda tidak boleh membuat keputusan desain berdasarkan asumsi kinerja. Anda membuat keputusan desain berdasarkan apa yang Anda anggap sebagai desain terbaik dan hanya jika profil di kehidupan nyata menunjukkan hambatan dalam desain, Anda dapat memperbaikinya. Biasanya jika desainnya bagus, performanya juga bagus.
Mecki
Dengan anggota pribadi, selain antarmuka publik, mereka tidak dapat melihat detail spesifik implementasi. Mereka hanya dapat membuka kelas dan mencarinya, jadi itu tidak masuk akal ?!
Black
2
@Black Clearly Allain berarti 'mereka tidak dapat mengakses ' anggota tersebut dan oleh karena itu tidak dapat membuat kode terhadap mereka, membiarkan penulis kelas bebas untuk menghapus / mengubah anggota yang dilindungi nanti. (Tentu saja, idiom pimpl akan memungkinkan untuk menyembunyikannya secara visual dan dari unit terjemahan termasuk tajuk, juga.)
underscore_d
31

Perasaan umum saat ini adalah bahwa mereka menyebabkan kopling yang tidak semestinya antara kelas turunan dan basisnya.

Mereka tidak memiliki keunggulan tertentu atas metode / properti yang dilindungi (pada suatu waktu mereka mungkin memiliki sedikit keunggulan kinerja), dan mereka juga lebih banyak digunakan di era ketika warisan yang sangat dalam sedang populer, yang saat ini tidak ada.

Will Dean
sumber
2
Tidak no particular advantage over protected methods/propertiesseharusnya no particular advantage over *private* methods/properties?
Penghe Geng
Tidak, karena saya sedang / sedang berbicara tentang keuntungan / kerugian dari berbagai cara berkomunikasi antara kelas turunan dan basisnya - semua teknik ini akan 'dilindungi' - perbedaannya adalah apakah mereka variabel anggota (bidang) atau properti / metode ( yaitu subrutin dari beberapa jenis).
Akankah Dean
1
Terima kasih atas klarifikasi singkatnya. Saya senang menerima balasan dari pengirim asli dalam satu jam untuk pertanyaan saya ke postingan berusia 6 tahun. Anda tidak berpikir itu bisa terjadi di kebanyakan forum online lainnya :)
Penghe Geng
9
Lebih luar biasa lagi adalah bahwa saya benar-benar setuju dengan diri saya sendiri selama waktu itu ...
Will Dean
Satu urutan urusan konstruktor adalah memastikan bahwa semua variabel status diinisialisasi secara eksplisit. Jika Anda mematuhi konvensi ini, Anda bisa menggunakan superkonstruksi untuk memanggil konstruktor induk; itu kemudian akan mengurus inisialisasi variabel keadaan privat di kelas induk.
ncmathsadist
31

Umumnya, jika sesuatu tidak sengaja dipahami sebagai publik, saya membuatnya pribadi.

Jika muncul situasi di mana saya memerlukan akses ke variabel atau metode privat tersebut dari kelas turunan, saya mengubahnya dari privat menjadi dilindungi.

Ini hampir tidak pernah terjadi - saya sama sekali bukan penggemar warisan, karena ini bukan cara yang baik untuk mencontoh kebanyakan situasi. Bagaimanapun, lanjutkan, jangan khawatir.

Saya akan mengatakan ini baik-baik saja (dan mungkin cara terbaik untuk melakukannya) untuk sebagian besar pengembang.

Fakta sederhananya adalah , jika beberapa pengembang lain datang setahun kemudian dan memutuskan bahwa mereka memerlukan akses ke variabel anggota pribadi Anda, mereka hanya akan mengedit kode, mengubahnya menjadi dilindungi, dan melanjutkan bisnis mereka.

Satu-satunya pengecualian nyata untuk ini adalah jika Anda berada dalam bisnis pengiriman dll biner dalam bentuk kotak hitam ke pihak ketiga. Ini pada dasarnya terdiri dari Microsoft, vendor 'Custom DataGrid Control', dan mungkin beberapa aplikasi besar lainnya yang dikirimkan dengan perpustakaan yang dapat diperpanjang. Kecuali Anda termasuk dalam kategori itu, tidak ada gunanya menghabiskan waktu / tenaga untuk mengkhawatirkan hal semacam ini.

Orion Edwards
sumber
8

Masalah utama bagi saya adalah bahwa setelah Anda membuat variabel yang diproteksi, Anda tidak dapat mengizinkan metode apa pun di kelas Anda untuk mengandalkan nilainya berada dalam kisaran, karena subkelas selalu dapat menempatkannya di luar jangkauan.

Misalnya, jika saya memiliki kelas yang menentukan lebar dan tinggi objek yang dapat dirender, dan saya membuat variabel tersebut dilindungi, maka saya tidak dapat membuat asumsi atas (misalnya), rasio aspek.

Secara kritis, saya tidak pernah dapat membuat asumsi tersebut kapan pun sejak kode dirilis sebagai pustaka, karena meskipun saya memperbarui setter saya untuk mempertahankan rasio aspek, saya tidak menjamin bahwa variabel disetel melalui setter atau diakses melalui getter dalam kode yang ada.

Juga tidak ada subclass dari kelas saya yang memilih untuk membuat jaminan itu, karena mereka juga tidak dapat menerapkan nilai variabel, bahkan jika itu adalah inti dari subclass mereka .

Sebagai contoh:

  • Saya memiliki kelas persegi panjang dengan lebar dan tinggi disimpan sebagai variabel yang dilindungi.
  • Sub-kelas yang jelas (dalam konteks saya) adalah kelas "DisplayedRectangle", di mana satu-satunya perbedaan adalah saya membatasi lebar dan tinggi ke nilai yang valid untuk tampilan grafis.
  • Tapi itu tidak mungkin sekarang , karena kelas DisplayedRectangle saya tidak dapat benar - benar membatasi nilai-nilai itu, karena setiap subkelasnya dapat menimpa nilai secara langsung, sementara masih diperlakukan sebagai DisplayedRectangle.

Dengan membatasi variabel menjadi privat, saya kemudian dapat menerapkan perilaku yang saya inginkan melalui penyetel atau pengambil.

deworde.dll
sumber
7

Secara umum, saya akan menyimpan variabel anggota terlindungi Anda pada kasus yang jarang terjadi di mana Anda memiliki kendali penuh atas kode yang menggunakannya juga. Jika Anda membuat API publik, saya akan mengatakan tidak pernah. Di bawah ini, kita akan menyebut variabel anggota sebagai "properti" dari objek.

Inilah yang tidak bisa dilakukan superclass Anda setelah membuat variabel anggota dilindungi daripada private-with-accessor:

  1. dengan malas membuat nilai dengan cepat saat properti sedang dibaca. Jika Anda menambahkan metode getter yang dilindungi, Anda dapat dengan malas membuat nilai dan meneruskannya kembali.

  2. tahu kapan properti itu diubah atau dihapus. Ini dapat menyebabkan bug ketika superclass membuat asumsi tentang status variabel itu. Membuat metode penyetel yang dilindungi untuk variabel mempertahankan kontrol itu.

  3. Setel breakpoint atau tambahkan output debug saat variabel dibaca atau ditulis.

  4. Ubah nama variabel anggota itu tanpa mencari semua kode yang mungkin menggunakannya.

Secara umum, saya pikir itu akan menjadi kasus yang jarang terjadi ketika saya merekomendasikan membuat variabel anggota yang dilindungi. Anda lebih baik menghabiskan beberapa menit untuk mengekspos properti melalui pengambil / penyetel daripada berjam-jam kemudian melacak bug di beberapa kode lain yang memodifikasi variabel yang dilindungi. Tidak hanya itu, Anda juga diasuransikan untuk tidak menambahkan fungsionalitas masa depan (seperti pemuatan lambat) tanpa merusak kode dependen. Lebih sulit melakukannya nanti daripada melakukannya sekarang.

Michael Bishop
sumber
7

Pada tingkat desain mungkin tepat untuk menggunakan properti yang dilindungi, tetapi untuk implementasi saya tidak melihat keuntungan dalam memetakan ini ke variabel anggota yang dilindungi daripada metode pengakses / mutator.

Variabel anggota yang dilindungi memiliki kerugian yang signifikan karena mereka secara efektif memungkinkan kode klien (sub-kelas) akses ke keadaan internal kelas kelas dasar. Ini mencegah kelas dasar dari secara efektif mempertahankan invariannya.

Untuk alasan yang sama, variabel anggota yang dilindungi juga membuat penulisan kode multi-utas yang aman jauh lebih sulit kecuali dijamin konstan atau terbatas pada utas tunggal.

Metode aksesor / mutator menawarkan stabilitas API dan fleksibilitas implementasi yang jauh lebih besar dalam pemeliharaan.

Selain itu, jika Anda seorang OO purist, objek berkolaborasi / berkomunikasi dengan mengirim pesan, bukan membaca / menyetel status.

Sebagai gantinya, mereka menawarkan sedikit keuntungan. Saya tidak perlu menghapusnya dari kode orang lain, tetapi saya tidak menggunakannya sendiri.

richj
sumber
4

Sebagian besar waktu, berbahaya menggunakan protected karena Anda merusak enkapsulasi kelas Anda, yang bisa dipecah dengan baik oleh kelas turunan yang dirancang dengan buruk.

Tapi saya punya satu contoh bagus: Katakanlah Anda bisa beberapa jenis wadah umum. Ini memiliki implementasi internal, dan pengakses internal. Tapi Anda perlu menawarkan setidaknya 3 akses publik ke datanya: map, hash_map, vector-like. Kemudian Anda memiliki sesuatu seperti:

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

Saya menggunakan kode semacam ini kurang dari sebulan yang lalu (jadi kodenya dari memori). Setelah beberapa pemikiran, saya percaya bahwa sementara wadah Basis generik haruslah kelas abstrak, bahkan jika itu dapat hidup cukup baik, karena menggunakan Basis secara langsung akan sangat merepotkan, itu harus dilarang.

Ringkasan Jadi, Anda telah melindungi data yang digunakan oleh kelas turunan. Namun, kita harus memperhitungkan fakta bahwa kelas Base harus abstrak.

paercebal.dll
sumber
itu tidak merusak enkapsulasi lagi daripada anggota publik. Ini adalah pengaturan untuk mengatakan bahwa kelas turunan dapat menggunakan status kelas yang tidak diekspos ke pengguna kelas.
gbjbaanb
@gbjbaanb: Anda mengkontradiksi diri Anda sendiri "itu tidak merusak enkapsulasi lagi daripada yang dilakukan anggota publik" berbeda dari "[hanya] kelas turunan yang dapat menggunakan kelas 'status". "dilindungi" adalah pertengahan antara publik dan pribadi. Jadi "dilindungi [...] agak merusak enkapsulasi" masih benar ...
paercebal
sebenarnya, dalam bahasa c ++, adaptor kontainer seperti std :: stack akan mengekspos objek kontainer yang mendasari dengan variabel terlindungi yang disebut "c".
Johannes Schaub - litb
Saya tahu posting ini cukup lama, tetapi saya merasa perlu untuk ikut campur. Anda tidak "agak" merusak enkapsulasi, Anda benar-benar merusaknya. protectedtidak lebih dikemas dari public. Saya bersedia terbukti salah. Yang harus Anda lakukan adalah menulis kelas dengan anggota yang dilindungi dan melarang saya untuk memodifikasinya. Jelas kelas harus non-final, karena inti dari penggunaan protected adalah untuk warisan. Entah ada sesuatu yang dikemas, atau tidak. Tidak ada negara bagian di antara keduanya.
Taekahn
3

Singkatnya, ya.

Variabel anggota yang dilindungi memungkinkan akses ke variabel dari sub-kelas apa pun serta kelas apa pun dalam paket yang sama. Ini bisa sangat berguna, terutama untuk data hanya-baca. Saya tidak percaya bahwa mereka pernah diperlukan, karena setiap penggunaan variabel anggota yang dilindungi dapat direplikasi menggunakan variabel anggota pribadi dan beberapa getter dan setter.

Jay Stramel
sumber
1
Sebaliknya, variabel anggota pribadi juga tidak pernah dibutuhkan; publik cukup untuk penggunaan apapun.
Alice
3

Sebagai catatan, di bawah Item 24 dari "C ++ Luar Biasa", di salah satu catatan kaki, Sutter berkata "Anda tidak akan pernah menulis kelas yang memiliki variabel anggota publik atau dilindungi. Kan? (Terlepas dari contoh buruk yang ditetapkan oleh beberapa perpustakaan .) "

hAcKnRoCk
sumber
2

Untuk info mendetail tentang pengubah akses .net buka di sini

Tidak ada keuntungan atau kerugian nyata untuk variabel anggota yang dilindungi, ini adalah pertanyaan tentang apa yang Anda butuhkan dalam situasi khusus Anda. Secara umum, praktik yang dapat diterima untuk mendeklarasikan variabel anggota sebagai pribadi dan mengaktifkan akses luar melalui properti. Juga, beberapa alat (misalnya beberapa pembuat peta O / R) mengharapkan data objek diwakili oleh properti dan tidak mengenali variabel anggota publik atau dilindungi. Tetapi jika Anda tahu bahwa Anda ingin subclass Anda (dan HANYA subclass Anda) untuk mengakses variabel tertentu, tidak ada alasan untuk tidak mendeklarasikannya sebagai dilindungi.

Manu
sumber
Menginginkan subkelas untuk mengakses variabel sangat berbeda dengan menginginkan mereka dapat dengan bebas mengubahnya . Itulah salah satu argumen utama terhadap variabel yang dilindungi: sekarang kelas dasar Anda tidak dapat mengasumsikan salah satu invariannya yang dipegang, karena kelas turunan apa pun dapat melakukan apa pun dengan anggota yang dilindungi. Itulah argumen utama yang menentang mereka. Jika mereka hanya perlu mengakses data, maka ... tulis pengakses . : P (Saya memang menggunakan variabel yang dilindungi, meskipun mungkin lebih dari yang seharusnya, dan saya akan mencoba menghentikannya!)
underscore_d