Neden özel alanlar var, yeterince korunmuyorlar?


265

privateSınıf alanlarının / özelliklerinin / niteliklerinin görünürlüğü faydalı mı? OOP'da er ya da geç, bir sınıfın alt sınıfını yapacaksınız ve bu durumda, uygulamayı tamamen değiştirebilmeniz ve anlayabilmeniz iyidir.

Bir sınıfı alt sınıflarken yaptığım ilk şeylerden biri, bir sürü privateyöntemi değiştirmektir protected. Bununla birlikte, dış dünyadan ayrıntıları gizlemek önemlidir - bu yüzden sadece ihtiyacımız protecteddeğil public.

Sorum şu: OOP dilleri için iyi bir araç privateyerine, bunun yerine protectediki seçenek " protected& public" yeterli midir , önemli bir kullanım durumu biliyor musunuz ?



236
Seçmenlere: OP'nin öncüllerine de kesinlikle katılmıyorum, ancak bu soruyu destekliyorum çünkü mükemmel bir şekilde tutarlı ve cevap vermeye değer. Evet, OP'nin bunun neden yanlış olduğunu anlatması gerekiyor, ancak bunu yapmanın yolu, henüz kendisi için henüz bir şey çözemediği için bir cevap yazmak (ya da mevcut cevapları düzenlemeyi önermek).
Ixrec 11:16

18
Türetilmiş sınıflar dış dünyanın bir parçasıdır.
CodesInChaos

20
Korumanın her zaman erişimin miras hiyerarşisine kilitlendiği anlamına gelmediğini unutmayın. Java'da ayrıca paket düzeyinde erişim sağlar.
berry120

8
Profesörüm, "Çocuklarıma söylemediğim şeyler var. Özel alanlarımdır" derdi.
SáT

Yanıtlar:


225

Çünkü dediğiniz gibi, sizi protectedhala "uygulamayı tamamen değiştirebilme" seçeneğine bırakıyor. Sınıf içindeki hiçbir şeyi gerçekten korumaz.

Neden sınıf içindeki şeyleri “gerçekten korumayı” önemsiyoruz? Çünkü aksi takdirde , uygulama kodunu müşteri kodunu bozmadan değiştirmek mümkün olmaz . Başka bir deyişle, alt sınıf yazan insanlar aynı zamanda orijinal üs sınıfını yazan kişi için “dış dünya” dır.

Uygulamada, protectedüyeler aslında bir sınıf olan "alt sınıflar için genel API" dir ve publicüyelerin olduğu gibi sabit ve geriye dönük kalmaları gerekir . Gerçek privateüyeler oluşturma yeteneğine sahip olmasaydık, bir uygulamadaki hiçbir şey asla güvenli olmazdı, çünkü (kötü amaçlı olmayan) müşteri kodunun bir şekilde bağlı kalması olasılığını ekarte edemezsiniz. o.

Bu arada, "OOP'de er ya da geç, bir sınıfın alt sınıfını yapacaksınız" teknik olarak doğru olsa da, argümanınız, "er ya da geç, bir alt sınıf yapacaksınız" Her sınıf "ki neredeyse kesinlikle durum böyle değil.


11
Yapabilseydim seni + 1'den fazla fırlatırdım, çünkü bu benim için ilk kez privatemantıklıydı. Lib perspektifinin daha sık kullanılması gerekir, aksi halde (C-benzeri) “mutlak kontrol, mutlak sorumluluk” kodlama zihniyetine düşkün olan herkes onu “beni kendimden koruyor” olarak işaretleyebilir. Hala privatedaha önce kullandığımı , sadece her zaman iyi bir dokümantasyon hissettim ve _foodaha iyi olmasa bile muhtemelen onunla uğraşmaması gerektiğini belirtmek gibi bir adlandırma kuralı hissettim . Kararlı bir şekilde "hiçbir şeyin kırılmayacağını" söyleyebilmek meşru, tek başına bir privateözelliktir.
abluejelly

Aslen halk kütüphaneleri ve çerçeveleri kodunu görmezden geldim ve sadece "müşteri kodu" açısından az çok düşündüm. Dahili uygulamayı optimize etmek soruma iyi bir örnek, kendime şunu sorsam da, gerçekte bunun gerçekten gerçekleşip gerçekleşmediğini (özellikle de bir sınıf bir öğrencinin 1000 kod satırından uzun olmamasını önerdiğinde) soruyorum. Genel olarak, Ruby'nin yaklaşımını seviyorum, ki burada özel bir öneriydi: "İşte ejderhalar olun, dikkatli olun".
Adam Libuša

9
@ AdamLibuša Kodunuz herkese açıksa, bu çok daha büyük bir anlaşma olsa da, sınıfın tüm müşterilerinin yazarı olsanız bile, hala geçerlidir. Sorun, basitçe bazı refraktörlerin imkansız olması, belirli refraktörlerin sıkıcı ve hataya açık olması nedeniyle değişiyor . Optimizasyon aslında benim deneyimlerimde bu refactors için en az nedendir (çoğunlukla Javascript yapsam da), genellikle elde etmek için çeşitli iç bitlerin bağımlılık / çağrı grafiğinin yeniden yapılandırılmasını gerektiren temel bir uygulama kusurunu açığa çıkaran bir hata gibidir. gerçekten sağlam bir düzeltme.
Ixrec

5
"" er ya da geç, her sınıfın bir alt sınıfını yapacaksın "neredeyse kesinlikle durum böyle değil." Ve daha da önemlisi, neredeyse kesinlikle olmayacaksınız ve kesinlikle bir sınıftaki her işlevi geçersiz kılmalısınız ve bir sınıftaki her veri öğesinin kullanımını değiştirmelisiniz. Sınıfın bir anlamı olması için bazı şeylerin mantıklı bir şekilde taşa yazılması gerekir.
Jay

1
Eğer yapabilseydim, seni + 1'den daha fazla fırlatırdım => Buna ödül denirdi @ abluejelly
Thomas Ayoub

256

OOP'da er ya da geç, sınıfın bir alt sınıfını yapacaksınız.

Bu yanlış. Her sınıfın alt sınıf olması amaçlanmamıştır ve bazı statik olarak yazılmış OOP dilleri, örneğin final(Java ve C ++) veya sealed(C #) gibi engelleyici özelliklere sahiptir .

Uygulamayı tamamen değiştirebilmek ve anlamakta fayda var.

Hayır değil. Bir sınıfın, kamusal arayüzünü açıkça tanımlayabilmesi ve değişkeni olsa bile değişmezlerini koruyabilmesi iyi bir şeydir.

Genel olarak, erişim kontrolü bölümlendirmeyle ilgilidir. Kodun tek bir bölümünün, kodun geri kalanıyla nasıl etkileşimde bulunduğunu ayrıntılı olarak anlamak zorunda kalmadan anlaşılmasını istiyorsunuz. Özel erişim buna izin verir. Her şey en azından korunuyorsa, temel sınıfın nasıl çalıştığını anlamak için her alt sınıfın ne yaptığını anlamanız gerekir.

Veya onu Scott Meyers terimine sokmak: bir sınıfın özel bölümleri sınırlı miktarda koddan etkilenir: sınıfın kodu.

Ortak bölümler, var olan her kod biti ve sınırsız miktarda bir kod olan henüz yazılmamış olan her bir kod bitiğinden etkilenir.

Korunan parçalar mevcut her alt sınıftan ve henüz yazılmamış olan her alt sınıftan etkilenebilir; bu da sonsuz miktarda bir koddur.

Sonuç olarak, korunan size halktan çok daha az şey verir, oysa ki özel size gerçek bir gelişme sağlar. Özel değil sorgulanabilir erişim korumalı özelliğinin varlığıdır.


34
"Sınırsız miktarda koddan etkilenen" teorik senaryosu için +1
Broken_Window

13
Belki de, C # tasarımcılarının, aslında virtualbu cevabın ana hatları ile belirtilen nedenlerden dolayı açıkça belirtilmediği sürece, miras alınan bir yöntemi geçersiz kılmayı yasaklamaya karar vermelerine değer.
Vousden,

11
Ya da basitçe söylemek gerekirse: protectedveri üyeleri için değil, yöntemler içindir.
Matthieu M.,

7
Şimdi bulamıyorum, ancak @EricLippert'in MS sealed. 3. parti mirasçıların dahili değerlere dokunmalarına izin verdiğiniz an, her yönteme büyük miktarda doğrulama / akıl yürütme kontrolü eklemeniz gerekir, çünkü nesnelerin iç durumu hakkında hiçbir tasarım değişmezine artık güvenemezsiniz.
Dan Neely,

4
@ ThorbjørnRavnAndersen "geliştirirken ancak yayınlandığında değil" - nasıl bir sınıf bilmeli? Gerçekten, sürüm sürümünü bile test edemediğinizde, sürümden farklı bir deneme sürümü derlemek ister misiniz? Testlerin yine de özel eşyalara erişmesi gerekmemeli.
Sebastian Redl, 14.06

33

Evet, özel alanlar kesinlikle gereklidir. Sadece bu hafta, sözlüğe ne konulduğunu kontrol ettiğim özel bir sözlük uygulaması yazmam gerekiyordu. Sözlük alanı korunacak ya da halka açıklanacak olsaydı, o zaman dikkatlice yazdığım kontroller kolayca üstesinden gelinebilirdi.

Özel alanlar, tipik olarak, verilerin beklenen orijinal kodlayıcı gibi olmasını güvence altına almakla ilgilidir. Her şeyi korumalı / halka açık yapın ve bu prosedürler ve validasyonla bir koç ve ata binin.


2
"Antrenör ve atlara biniş" için +1. Daha fazla duymak isterdim harika bir cümle.
Nic Hartley

2
Birinin sınıfınızı alt sınıfa atması gerekiyorsa, belki de güvencelerinize erişimi olmalı? Ve birinin bir amaca ulaşmak için güvencelerinizi değiştirmesini istemiyorsanız, belki de kodu paylaşmayın. Ruby'de bu şekilde çalışır - özel bir öneriye az ya da çok.
Adam Libuša

3
@ AdamLibuša "Kodu paylaşma"? Herhangi bir DLL yayınladığınız anda kodu paylaşıyorsunuzdur - tüm yapıları ve yöntemleri ve her şey görebilmeniz için, özellikle varsayılan olarak yansımayı destekleyen dillerde. Herkes "kodunuzla" istediği her şeyi yapabilir - privatesadece "bunlara dokunma" demenin bir yolu ve derleyici sözleşmesi kapsamında yürürlüğe koyulması gerekir. .NET gibi sistemlerde, bunun da önemli güvenlik sonuçları vardır - yalnızca tam güven duyduğunuzda (temelde yönetici / kök erişiminin karşılığı) yalnızca başkalarının kişisel özelliklerine dokunabilirsiniz.
Luaan

2
@ AdamLibuša Sanırım kafa karışıklığınız çoğunlukla farklı dillerdeki farklı OOP yaklaşımlarından kaynaklanıyor. OOP'un kökü (başlangıçta tanımlandığı gibi) mesajlaşmadır - bu , yanıtladığınız mesajlar dışında her şeyin özel olduğu anlamına gelir . Çoğu OOPish dilinde, bu, kamu arabirimini olabildiğince küçük yapmanın bir yolu olan "verilerinizi gizli tutmanız" olarak ortaya çıkar. Kullanıcının (bir alt sınıf veya başka bir sınıf olması) sınıfınızı manipüle etmesinin tek yolu, tanımladığınız ortak arabirimdir - aracınızı sürmek için genellikle direksiyon simidini ve pedalları kullanma şeklinize benzer :)
Luaan

3
@Luaan +1, başkalarının haklarına dokunmak sorun değil!
Nigel Touch

12

Resmen mantığa çalışırken nesne yönelimli programın doğruluğu hakkında öyle tipik içeren modüler bir yaklaşım kullanmak nesne değişmezleri . Bu yaklaşımda

  1. Yöntemler onlarla ve sonrası koşullarla (sözleşmeler) ilişkilidir.
  2. Nesneler değişmezlerle onlarla ilişkilendirmişlerdir.

Bir cisim hakkında modüler akıl yürütme aşağıdaki gibi ilerler (ilk önce en azından yaklaşık bir değer)

  1. Nesnenin yapıcısının değişmezliği kurduğunu kanıtlayın
  2. Özel olmayan her yöntem için, değişmez nesne ve yöntem önkoşulunun girişte bekletildiğini varsayalım, sonra kodun gövdesinin, koşullu ve değişmeyen beklemede yöntemden çıkıldığını ima ettiğini ispatlayın

object AYukarıdaki yaklaşımı kullanarak doğruladığımızı hayal edin . Ve şimdi doğrulamak isteyen method gait object Bçağıran method farasında object A. Modüler akıl yürütme method g, uygulamasının yeniden gözden geçirilmesine gerek kalmadan akıl yürütmemizi sağlar method f. Tabii ki , çağrı sahasının değişmezliğini object Ave ön koşulunu belirleyebilirsek, yöntem şartının çağrısının davranışının bir özeti olarak post koşulunu alabiliriz . Üstelik çağrı döndükten sonra hala tutan değişmez değişkeni de öğreneceğiz .method fmethod g,method fA

Bu akıl yürütme modülerliği, resmen büyük programlar hakkında düşünmemize izin verir. Yöntemlerin her birini ayrı ayrı akıl yürütebilir ve daha sonra programın daha büyük bölümleri hakkında akıl yürütmek için bu akıl yürütmenin sonuçlarını oluşturabiliriz.

Özel alanlar bu süreçte çok faydalıdır. Bir nesnenin değişmezinin, bu nesne üzerindeki iki yöntem çağrısı arasında kalmaya devam ettiğini bilmek için, genellikle nesnenin araya girme döneminde değiştirilmediğine güveniriz.

Nesnelerin özel alanlarının olmadığı bir bağlamda çalışmak için modüler bir akıl yürütme için, o zaman bir alanın başka bir nesne tarafından ayarlanıp ayarlanmadığını, değişmezin her zaman yeniden kurulduğundan emin olmak için bir yol bulmamız gerekir. Ayarlamak). Nesnenin alanlarının değeri ne olursa olsun, her ikisinin de değişmeyen bir nesne olduğunu hayal etmek zordur ve ayrıca programın doğruluğunu düşünmek için de yararlıdır. Muhtemelen sahaya erişim konusunda karmaşık bir kongre icat etmemiz gerekecekti. Muhtemelen modüler olarak akıl yürütme yeteneğimizin bir kısmını (en kötüsünden bile olsa) kaybedersiniz.

Korunan alanlar

Korunan alanlar, modüler olarak akıl yürütme yeteneğimizin bir kısmını geri yükler. Dile bağlı olarak, protectedbir alanı tüm alt sınıflara veya tüm alt sınıflara ve aynı paket sınıflarına ayarlama yeteneği kısıtlayabilir. Genellikle yazdığımız bir nesnenin doğruluğunu düşünürken tüm alt sınıflara erişimimiz yoktur. Örneğin, daha sonra daha büyük bir programda (veya birkaç daha büyük programda) kullanılacak bir bileşeni veya kitaplığı yazıyor olabilirsiniz - bazıları henüz yazılmamış olabilir. Genelde alt sınıflandırılıp sınıflandırılmadığını ve hangi yollarla olduğunu bilmezsiniz.

Bununla birlikte, genişlettiği sınıfın değişmeyen nesnesini korumak genellikle alt sınıflarda görev yapar. Dolayısıyla, korumanın yalnızca "alt sınıf" anlamına geldiği bir dilde ve alt sınıfların her zaman üst sınıflarının değişmezlerini korumasını sağlamak için disiplinli olduğumuz bir dilde, özel kullanım yerine korumalı kullanım seçiminin yalnızca minimum modülerliği kaybettiğini iddia edebilirsiniz. .

Ben resmi muhakeme bahsediyor olmasına rağmen, edilir genellikle düşünce onların kod doğruluğu hakkında programcılar gayri nedeni bazen argümanlar benzer türdeki itimat zaman olduğu.


8

privateBir sınıftaki değişkenler, bir blok içindeki ifadenin protectedbir breakifadeden daha iyi olmasından aynı sebepten switchdaha iyidir goto label; ki insan programcıları hataya açık.

protectedDeğişkenler kasıtlı olmayan istismarlara (programcı hataları) gotoborç verir , tıpkı ifade spagetti kodunun oluşturulmasına borç verir.

protectedSınıf değişkenlerini kullanarak çalışma hatasız kod yazmak mümkün mü ? Evet tabi ki! Tıpkı çalışma hatasız kodunu kullanarak yazmak mümkün goto; ama klişe giderken "Sadece yapabileceğin, yapman gerektiği anlamına gelmez!"

Sınıflar ve gerçekten de OO paradigması, anlamsız hataya açık insan programcılarına hata yapmalarına karşı korunmak için var olur. İnsan hatalarına karşı savunma, yalnızca sınıfa yapılan savunma önlemleri kadar iyidir. Sınıfınızın uygulanmasını sağlamak, protectedkalenin duvarlarında devasa bir delik açmaya eşdeğerdir.

Temel sınıfların türetilmiş sınıflar hakkında hiçbir bilgisi yoktur. Temel bir sınıf söz konusu olduğunda, protectedaslında size daha fazla koruma sağlamaz public, çünkü türetilmiş bir sınıfı publicarka kapı gibi davranan bir alıcı / ayarlayıcı oluşturmaktan alıkoyan hiçbir şey yoktur .

Bir temel sınıf, iç uygulama ayrıntılarına engelsiz erişime izin verirse, sınıfın kendisinin hatalara karşı savunması imkansız hale gelir. Temel sınıfların türetilmiş sınıfları hakkında hiçbir bilgisi yoktur ve bu nedenle bu türetilmiş sınıflarda yapılan hatalara karşı korunma yolu yoktur.

Bir temel sınıfın yapabileceği en iyi şey, mümkün olduğu kadar çok uygulanmasını gizlemek privateve türetilmiş sınıflardan veya sınıfın dışındaki herhangi bir şeyden kaynaklanan değişikliklere karşı korunmak için yeterli kısıtlamaları koymaktır.

Sonuçta, insan hatalarını en aza indirmek için üst düzey diller mevcuttur. İnsan hatalarını en aza indirmek için iyi programlama uygulamaları (örneğin SOLID ilkeleri gibi ) da mevcuttur.

İyi programlama uygulamalarını görmezden gelen yazılım geliştiricilerin çok daha yüksek bir başarısızlık şansı vardır ve kırılmaz sürdürülemez çözümler üretme olasılıkları daha yüksektir. İyi uygulamaları takip edenler, çok daha düşük bir başarısızlık şansına sahipler ve çalışma açısından sürdürülebilir çözümler üretme olasılıkları daha yüksek.


Düşürücü adayına - bu cevapla ilgili olarak ne değiştirilebilir / iyileştirilebilir?
Ben Cottrell

Oyları düşürmedim, fakat erişim seviyesini mola / goto ile karşılaştırarak mı?
imel96

@ imel96 Hayır, kaçınılma nedenini karşılaştırarak ve "En İyi Uygulama" (özellikle yeni kod yazmak için ) tarafından önerilmemektedir . yani Yetkili bir programcı, publicsürdürülemez kodlara borç verdiğinden uygulama ayrıntılarından kaçınır . Yetkili bir programcı kaçınılmazdır gotoçünkü kendisini sürdürülemez kodlara borçludur. Bununla birlikte, gerçek dünya, bazen korkunç bir eski miras karmaşası içinde kaybolmuş olmanız ve kullanmaktan başka seçeneğiniz olmaması gotove aynı sebepten dolayı bazen kamuya açık / korunan uygulama detaylarını kullanmaktan başka seçeneğiniz yok.
Ben Cottrell 14.06

Şiddeti büyüklük bakımından farklıdır, kıyaslanamaz. Yalnızca publicözelliklere / arayüze sahip kodla yaşayabilirim , ancak yalnızca kullanılan kodlarla yaşayamam goto.
imel96

2
@ imel96 Hiç kullandığınız kodda çalıştınız mı gotoya da sadece böyle makaleleri okuduğunuz için mi? Neden goto kötü olduğunu anlıyorum çünkü 2 yıl boyunca onu kullanan eski kodda çalışıyorum; ve "sınıfların" uygulama ayrıntılarının her yere sızdığı publicve friendhızlı / kolay / kirli kesitler olarak kullanılan belirticilerin bulunduğu kodda daha uzun süre çalıştım . "Uygulama ayrıntılarını herkese açık gösterme" nin, ikizler arası spagetti karmaşasına gotokesinlikle aynı derecede önem verebileceği argümanını kabul etmiyorum .
Ben Cottrell

4

Devralınabilen sınıfların iki sözleşmesi vardır - biri nesne referansı sahiplerine ve türetilmiş sınıflara sahiptir. Kamu üyeleri referans sahipleri ile sözleşme ile bağlanır ve korunan üyeler türetilmiş sınıflarla sözleşme ile bağlanır.

Üyeler yapmak protected, onu daha çok yönlü bir temel sınıf yapar, ancak çoğu zaman sınıfın gelecekteki sürümlerinin değişebileceği yolları sınırlar. Üyeler yapmak private, sınıf yazarına, sınıfın iç işleyişini değiştirme konusunda daha çok yönlülük sağlar, ancak ondan faydalı bir şekilde elde edilebilecek sınıf türlerini sınırlandırır.

Örnek olarak, List<T>.NET'te destek deposunu özel yapan; Korunması halinde, türetilmiş türler başka türlü mümkün olmayan bazı faydalı şeyler yapabilirdi, ancak gelecekteki sürümleri, List<T>milyonlarca öğeyi tutan listeler için bile, tıknaz monolitik destek deposunu kullanmak zorunda kalacaktı. Destek deposunu özel yapmak, gelecekteki sürümlerinin List<T>türetilmiş sınıfları bozmadan daha verimli bir destek deposu kullanmasını sağlar.


4

Bence argümanınızda, birileri bir sınıf yazdığında, o sınıfı yoldan aşağıya kimin uzatacağını bilmeyeceklerini ve hangi sebepten dolayı bilmeyecekleri konusunda temel bir varsayım olduğunu düşünüyorum . Bu varsayım göz önüne alındığında, argümanınız mükemmel bir anlam ifade edecektir, çünkü o zaman özel yaptığınız her değişken, potansiyel olarak yoldaki bir gelişim yolunu kesebilir. Ancak, bu varsayımı reddederdim.

Bu varsayım reddedilirse, dikkate alınması gereken sadece iki durum vardır.

  1. Orijinal sınıfın yazarı, neden genişletilebileceği konusunda çok net fikirlere sahipti (örneğin, bir BaseFoo ve yolda birkaç somut uygulama olacak).

Bu durumda, yazar birisinin sınıfı genişleteceğini ve niçin korunacağını ve neyin gizli kalacağını tam olarak bileceğini bilir. Alt sınıfı oluşturan kullanıcıya bir çeşit arabirim iletmek için özel / korumalı ayrımı kullanıyorlar.

  1. Alt sınıfın yazarı bazı davranışları üst sınıfa sokmaya çalışıyor.

Bu durum nadir olmalı (meşru olmadığını iddia edebilirsiniz) ve orijinal sınıfı sadece orijinal kod tabanında değiştirmeyi tercih etmiyorsunuz. Ayrıca kötü tasarımın bir belirtisi olabilir. Bu gibi durumlarda, davranışı hackleyen kişinin sadece arkadaş (C / C ++) ve setAccessible(true)(Java) gibi diğer hack'leri kullanmasını tercih ederim .

Bu varsayımı reddetmenin güvenli olduğunu düşünüyorum.

Bu genellikle miras üzerindeki kompozisyon fikrine geri döner . Kalıtım, kod kullanımını yeniden azaltmanın ideal bir yolu olarak öğretilir, ancak nadiren kod kullanımı için ilk tercih olmalıdır. Basit bir yıkma tartışmam yok ve anlaşılması oldukça zor ve çekişmeli olabilir. Ancak, etki alanı modellemesi konusundaki deneyimimde, sınıfımı kimin ve neden miras alacağı konusunda çok net bir anlayış olmadan nadiren miras kullandığımı tespit ettim.


2

Her üç erişim seviyesi kendi kullanım durumlarına sahiptir, OOP hiçbirinde eksik kalmaya devam edecektir. Genellikle sen

  • tüm değişkenleri / veri üyelerini özel kılar . Dışarıdan birisinin dahili verilerinizi karıştırmasını istemiyorsunuz. Ayrıca, genel veya korunan arayüzünüze yardımcı işlevsellik (birkaç üye değişkenine dayanan hesaplamaları düşünün) sağlayan yöntemler - bu yalnızca dahili kullanım içindir ve ileride değiştirmek / iyileştirmek isteyebilirsiniz.
  • sınıfınızın genel arayüzünü herkese açık yapın . Orijinal sınıfınızın kullanıcılarının birlikte çalışması gereken ve türetilmiş sınıfların da nasıl görünmesi gerektiğini düşündüğünüzdür. Düzgün kapsülleme sağlamak için bunlar genellikle metotlardır (değişkenler değil, kullanıcının metotlarla çalışması için ne gerekiyorsa) (yalnızca yardımcı sınıflar / yapılar, enums'ler, typedef'ler).
  • Sınıfınızın işlevselliğini genişletmek / uzmanlaştırmak isteyen, ancak kamusal arabirimin bir parçası olmamalı olan, korunan yöntemleri beyan edin - aslında , gerektiğinde korunmaları için özel üyeler yetiştirirsiniz . Şüphen varsa, bunu bilene kadar
    1. sınıfınız alt olabilir / olabilir /
    2. ve alt sınıflamanın kullanım durumlarının ne olabileceği konusunda net bir fikir edin.

Ve bu genel şemadan saparsınız, ancak iyi bir sebep varsa ™ . "Dışarıdan serbestçe erişebildiğimde bu hayatımı kolaylaştıracak" dikkat edin (ve dışarısı da alt sınıfları içerir). Sınıf hiyerarşilerini uyguladığımda, genellikle alt sınıflandırma / genişletme / uzmanlaşma, bir çerçeve / araç setinin temel sınıfları olma ve bazen de orijinal işlevselliklerinin bir kısmını bir üst seviyeye taşıma aşamasına gelmeden, korumalı üyelere sahip olmayan sınıflarla başlarım.


1

Belki de daha ilginç bir soru, neden özelden daha başka herhangi bir alanın gerekli olduğudur. Bir alt sınıfın bir üst sınıfın verileriyle etkileşime girmesi gerektiğinde, bunu doğrudan yapmak, ikisi arasında doğrudan bir bağlantı oluşturur; oysa ikisi arasında etkileşimi sağlamak için yöntemleri kullanmak, aksi takdirde çok zor olurdu süper sınıf.

Bazı diller (örneğin Ruby ve Smalltalk) ortak alanlar sağlamaz, böylece geliştiricilerin sınıf uygulamalarına doğrudan eşleştirmeye izin vermekten vazgeçirilirler; Genel bir kayıp olmaz (çünkü süper sınıf her zaman alt sınıf için korumalı erişim sağlayıcıları sağlayabilir), ancak sınıfların her zaman en az küçük sınıflarından bir dereceye kadar izolasyon sağlamasını sağlar. Bu neden daha yaygın bir tasarım değil?


1

Burada çok güzel cevaplar var, ama yine de iki sentimi atacağım. :-)

Özel, aynı zamanda küresel verilerin kötü olması nedeniyle iyidir.

Bir sınıf özel verileri bildirirse, kesinlikle bu verilerle uğraşan tek kodun sınıftaki kod olduğunu biliyorsunuzdur. Bir hata olduğunda, bu verileri değiştirebilecek her yeri bulmak için tüm oluşturmayı taramanız gerekmez. Sınıfta olduğunu biliyorsun. Kodda bir değişiklik yaptığınızda ve bu alanın nasıl kullanıldığına ilişkin bir şeyi değiştirdiğinizde, bu alanı kullanabilecek tüm olası yerleri izlemeniz ve planlanan değişikliğinizin bunları kırabileceklerini incelemeniz gerekmez. Biliyorsun ki tek yerler sınıfın içinde.

Kütüphanede bulunan ve birden fazla uygulama tarafından kullanılan sınıflarda değişiklik yapmak zorunda kaldığım birçok kez yaşadım ve hakkında hiçbir şey bilmediğim bir uygulamayı kırmadığımdan emin olmak için çok dikkatli davranmam gerekiyor. Ne kadar halka açık ve korunan veri varsa, sorun için o kadar fazla potansiyel var.


1

Bazı muhalif fikirlerden bahsetmeye değeceğini düşünüyorum.

Teoride, diğer cevaplarda belirtilen tüm sebeplerden dolayı erişim seviyesini kontrol altına almak iyidir.

Uygulamada, kod incelemesi sırasında çok sık, erişim seviyesini özel -> korumalı ve çok sık korumalı -> halktan değil (özel kullanmak isteyenler) görüyorum. Neredeyse her zaman, sınıf özelliklerini değiştirmek, ayarlayıcıları / alıcıları değiştirmeyi içerir. Bunlar zamanımı (kod incelemesi) ve onların (kod değiştirmeyi) boşa harcıyor.

Ayrıca, sınıflarının değişiklik için kapalı olmadığı anlamına da geliyor.

İhtiyacınız olduğunda her zaman değiştirebileceğiniz iç koddaydı. Kod değiştirmek o kadar kolay olmadığında üçüncü parti kodla durum daha kötü.

Peki kaç programcı bunun bir güçlük olduğunu düşünüyor? Özel olmayan programlama dilleri kaç tane kullanıyor? Tabii ki, insanlar sadece bu dilleri kullanmıyorlar çünkü özel tanımlayıcıları yok, fakat dilleri basitleştirmeye yardımcı oluyorlar ve basitlik önemli.

IMO, dinamik / statik yazmaya çok benzer. Teoride statik yazım çok iyidir. Uygulamada, sadece hataların% 2 gibi engeller Dinamik Yazma mantıksız Etkinliği ... . Özel kullanmak muhtemelen hatayı ondan daha az engeller.

SOLID ilkelerinin iyi olduğunu düşünüyorum, insanların kamuya açık, korunan ve özel bir sınıf oluşturmayı umduğundan daha fazla umursayacağını diliyorum.


1
Kullanırken 3. taraf kodunu değiştirmeniz gerekirse, ya iyi tasarlanmış değil, ya da tekrar kullanmıyorsunuz. Soyut olmayan bir sınıfı, kapsüllenerek her zaman yeniden kullanabilirsiniz, ancak pratikte, neredeyse hiç alt sınıfa ihtiyacınız yoktur.
Küçük Santi

0

Ayrıca neden protectedyeterli olmadığına dair başka bir pratik örnek daha eklemek istiyorum . Üniversitemde ilk yıllar, bir masa oyununun bir masaüstü versiyonunu geliştirmek zorunda oldukları (daha sonra bir AI için geliştirildiği ve bir ağ üzerinden diğer oyunculara bağlandığı) bir proje yürütmektedir. Test çerçevesi dahil, başlamalarını sağlamak için bazı kısmi kodlar sağlanmıştır. Ana oyun sınıfının özelliklerinden bazıları, protectedbu sınıfı genişleten test sınıflarının bunlara erişimi olacak şekilde ortaya çıkar. Ancak bu alanlar hassas bilgi değildir.

Birimi için bir TA olarak ben sık sık öğrencilerin sadece tüm katma kod yapma bkz protectedveya public(diğer testere belki protectedve publicmalzeme ve onların da aynı olmalıdır varsayılır). Onlara neden koruma seviyelerinin uygun olmadığını ve birçoğunun nedenini bilmediğini soruyorum. Cevap, alt sınıflara maruz bıraktıkları hassas bilgilerin, başka bir oyuncunun bu sınıfı basitçe genişleterek ve oyun için oldukça hassas bilgilere erişerek hile yapabileceği anlamına gelir (aslında rakiplerin gizli konumu, sanırım nasıl olurdu? Bazı sınıfları uzatarak rakiplerinizi bir savaş gemisinde görmek mümkün). Bu, kodlarını oyun bağlamında çok tehlikeli kılar.

Bunun dışında, bir şeyi alt sınıflarınıza bile özel tutmak için birçok neden var. Mutlaka ne yaptıklarını bilmeyen bir kişi tarafından değiştirilirse, sınıfın doğru çalışmasını engelleyebilecek uygulama ayrıntılarını gizlemek olabilir (çoğunlukla kodunuzu burada kullanan diğer kişiler hakkında düşünün).


1
Anlamadım Oyun çalışırken oyuncular dinamik olarak sınıfları genişletmiyorlarsa, bu hile yapmak için nasıl kullanılabilir? Bu, güvenilmeyen kodu kod tabanınıza içe aktardığınız anlamına gelir. Öğrencilere derlenmiş sınıflar verdiğinizi ve uygulama detaylarını değiştirerek ödevlerini aldatmalarını engellediğinizi söylüyorsanız, koruma seviyesi ayarlamak ödevi daha güvenli hale getirmez. Öğrenciler kütüphaneleri parçalayabilir veya yansımalarını avantajlarına kullanabilirler. Bu elbette peşinde olduğunuz uygulama seviyesine bağlıdır.
Sam

@ sam Genellikle kod, daha sonra değişiklik yapan birisinin, içindeki kod kodunun tamamını bilmesi gerekmeyeceği varsayımıyla yazılmalıdır. Bu zaman zaman orjinal yazar bile olabilir (zaman geçtikçe, uyku eksikliği ...). Hile, öğrencilere ete kemiğe geçmeleri için iskelet kodu verilmesi ve dokunmaması gereken değişen mantık olabilir.
Phil Lello

0

Özel yöntemler / değişkenler genellikle bir alt sınıftan gizlenir. Bu iyi bir şey olabilir.

Özel bir yöntem, parametreler hakkında varsayımlarda bulunabilir ve arayanın kontrolünü akılda bırakabilir.

Korumalı bir yöntem girdilerin kontrolünü sağlamalıdır .


-1

"özel" şu anlama gelir: Sınıfın kendisi dışındaki hiç kimse tarafından değiştirilme veya erişilemez. Alt sınıflar tarafından değiştirilmesi veya erişilmesi amaçlanmamıştır. Alt sınıflar? Hangi alt sınıflar? Bunu alt sınıfa sokmamanız gerekiyor!

"korumalı" şu anlama gelir: Yalnızca sınıflar veya alt sınıflar tarafından değiştirilmesi veya erişilmesi amaçlanır. Muhtemelen alt sınıfı almanız gerektiğinden kesinti, aksi halde neden "özel" değil "korun" mu?

Burada açık bir fark var. Özel bir şey yaparsam, kirli parmaklarını uzak tutman gerekirdi. Bir alt sınıf olsan bile.


-1

Bir sınıfı alt sınıfa koyarken yaptığım ilk şeylerden biri, bir sürü özel yöntemi korumalı olarak değiştirmek.

Hakkında bazı muhakeme privatevs protected yöntemlerle :

privateyöntemler kodun yeniden kullanımını engeller. Bir alt sınıf, kodu özel yöntemde kullanamaz ve tekrar uygulamak zorunda kalabilir - ya da başlangıçta özel yönteme bağlı olan yöntemleri / yöntemleri yeniden uygulayabilirsiniz & c.

Öte yandan, herhangi bir yöntem değil private anlamında sınıfa "dış dünya" tarafından sağlanan bir API olarak görülebilir, üçüncü taraf alt sınıfları "dış dünya" da, bir başkası onun cevabını önerildiği gibi dikkate alınmasını zaten.

Bu kötü bir şey mi? - Sanmıyorum.

Elbette, bir (sözde) genel API, orijinal programlayıcıyı kilitler ve bu arayüzlerin yeniden yapılandırılmasını engeller. Ancak diğer taraftan da görüldü, neden bir programcı kendi "uygulama ayrıntılarını" kendi genel API'si kadar temiz ve kararlı bir şekilde tasarlamamalı? privateÖzel kodunu yapılandırma konusunda özensiz olması için kullanmalı mı? Kimse farketmeyeceği için belki daha sonra temizleyebileceğini mi düşünüyorsun? - Hayır.

Programcı, "özel" koduna da az düşünmeli, ilk etapta mümkün olduğu kadar tekrar kullanılmasını sağlayacak veya hatta teşvik edecek şekilde yapılandırmalıdır. Öyleyse, özel olmayan bölümler gelecekte bir korku kadar bir yük haline gelmeyebilir.

Gördüğüm pek çok (çerçeve) kod, tutarsız bir kullanım benimsiyor private: protectedözel bir metoda devredilmekten başka bir şey yapmaktan başka bir şey yapmayan son olmayan yöntemler. protectedsözleşmesi ancak özel alanlara doğrudan erişim yoluyla gerçekleştirilebilecek nihai olmayan yöntemler.

Bu yöntemler, mantıksal olarak geçersiz kılınamaz / geliştirilemez, ancak teknik olarak bunu (derleyici) açıklığa kavuşturmak için hiçbir şey yoktur.

Uzatılabilirlik ve miras ister misiniz? Yöntemlerini yapma private.

Sınıfınızın belirli davranışlarının değişmesini istemiyor musunuz? Yöntemlerini yap final.

Gerçekten de yönteminiz belli, iyi tanımlanmış bir bağlamın dışında çağrılamaz mı? Yönteminizi yapın privateve / veya gerekli iyi tanımlanmış içeriği başka bir protectedsarmalayıcı yöntemiyle yeniden kullanmak için nasıl kullanılabilir hale getirebileceğinizi düşünün .

Bu yüzden privateaz miktarda kullanmayı savunuyorum . Ve karıştırmamak privateiçin final. - Bir yöntemin uygulanması sınıfın genel sözleşmesi için hayati öneme sahipse ve bu nedenle değiştirilmemesi / geçersiz kılmaması gerekiyorsa, yapın final!

Alanlar için, privategerçekten fena değil. Alan (lar) makul bir şekilde uygun yöntemlerle "kullanılmış" olduğu sürece ( ya da değil !).getXX()setXX()


2
-1 Bu, orijinal soruya privatekarşı değil protected, yanlış tavsiye veriyor (“ privateaz miktarda kullanın ”?) Ve OO tasarımı konusundaki genel fikir birliğine aykırı. Kullanılması privateözensiz kod gizleme ile ilgisi yoktur.
Andres F.

3
Bir sınıfın bir API'sine sahip olduğunu söylersiniz, ancak API kullanıcısının, bilmek zorunda olmadıkları ayrıntılarla uğraşmak istemediği bağlantıyı kurmuş gibi görünmediğini söylersiniz. Bir sınıfın kullanıcısı için ideal durum, arayüzün sadece ihtiyaç duyduğu yöntemleri içermesi ve başka hiçbir şey içermemesidir. Yöntem yapmak private, API'yi temiz tutmaya yardımcı olur.
Ben Cottrell

1
@HannoBinder Sertlikten muzdarip bir sürü sınıf olduğu konusunda hemfikirim, ancak esneklik ve kodların yeniden kullanımı kapsülleme ve uzun süreli bakımdan çok daha az önemli. Tüm sınıfların korumalı üyelere sahip olduğu ve türetilmiş sınıfların, arzu ettikleri uygulama ayrıntılarıyla uğraşabileceği durumunuzu göz önünde bulundurun; Henüz yazılı olmayan kodun herhangi bir bölümündeki herhangi bir şeyin bu kodun herhangi bir zamanda başarısız olmasına neden olabileceğini bilerek bu sınıfları nasıl güvenle test edebilirsiniz? Kod, hepsi büyük bir çamur topuna dönüşmeden önce kaç tane "saldırıya" neden olabilir?
Ben Cottrell

2
Oh, "üyeler" dedin. Söylediğim şey sadece yöntemlere atıfta bulunmak . Üye değişkenleri (alanlar), gizliliğin çok daha haklı olduğu farklı bir hikayedir.
JimmyB

2
Tartışmadaki isimlendirme, her yere yayılmıştır çünkü belirli bir dile özgü değildir. C ++ 'da "Üye" veri, işlev, tür veya şablon olabilir.
JDługosz

-1

Korunmak yerine özel bir aracın iyi bir araç olduğu ya da OOP dilleri için "korunan ve halka açık" olmak üzere iki seçeneğin yeterli olabileceği önemli bir kullanım durumu hakkında bilginiz var mı?

Özel : herhangi bir alt sınıfın çağırması veya geçersiz kılması için hiçbir zaman yararlı olmayacak bir şeyiniz olduğunda.

Korumalı : alt sınıfa özgü bir uygulama / sabit olan bir şeye sahip olduğunuzda.

Bir örnek:

public abstract Class MercedesBenz() extends Car {
  //Might be useful for subclasses to know about their customers
  protected Customer customer; 

  /* Each specific model has its own horn. 
     Therefore: protected, so that each subclass might implement it as they wish
  */
  protected abstract void honk();

  /* Taken from the car class. */
  @Override
  public void getTechSupport(){
     showMercedesBenzHQContactDetails(customer);
     automaticallyNotifyLocalDealer(customer);
  }

  /* 
     This isn't specific for any subclass.
     It is also not useful to call this from inside a subclass,
     because local dealers only want to be notified when a 
     customer wants tech support. 
   */
  private void automaticallyNotifyLocalDealer(){
    ...
  }
}

2
herhangi bir alt sınıfın çağırması veya geçersiz kılması için hiçbir zaman yararlı olmayacak bir şeye sahip olduğunuzda - Ve bence, önceden asla bilemeyeceğiniz bir şey.
Adam Libuša

CMOS'umdaki sıfırlama düğmesine de basmam gerekebilir. Ancak varsayılan varsayım, buna gerçekten ihtiyacım olmayacağı ve bu nedenle de kasanın içine yerleştirildiği varsayımıdır. Aynı yöntem için de geçerli. Alt sınıfın kesinlikle yeniden yerleştirmesi / çağırması gerekiyorsa, korumalı hale getirirsiniz (bkz: honking). Diğer tarafların araması gerekiyorsa, herkese açık yaparsın.
Arnab Datta

-2

Bu konuyu anlamak benim için zordu, bu yüzden deneyimlerimin bir bölümünü paylaşmak istiyorum:

  • Nedir korunan alan? Bu var başka bir şey , yani bir sınıf dışında erişilemez bir alanda, daha kamuya böyle: $classInstance->field. Ve bunun hilesi "budur". Sınıfınızın çocukları buna tamamen erişebilecek, çünkü bu onların haklı iç kısmı.
  • Nedir özel alan? Kendi sınıfınız ve bu sınıfı kendi uygulamanız için " gerçek bir özel " . Tıpkı bir biberonda olduğu gibi "Çocukların erişemeyeceği yerlerde tutun". Sınıfınızın türevlerinin, yöntemlerin - çağrıldığında - bildirdiğiniz şeyin tam olarak kesinleşmeyeceğine dair bir garantiniz olacak

GÜNCELLEME: Çözdüğüm gerçek bir görevle pratik bir örnek. İşte burada: USB veya LPT gibi bir kartınız var (bu benim davamdı) ve bir ara katman yazılımınız var. Belirteç sizden bir pin kodu ister, doğru olup olmadığını açar ve şifrelenmiş kısmı ve deşifre edilecek bir dizi anahtar gönderebilirsiniz. Anahtarlar belirteçte saklanır, okuyamazsınız, sadece kullanın. Ve bir oturum için geçici anahtarlar vardı , bir belirteçte bir anahtarla imzalandı, ancak ara katman yazılımında saklandı. Temp tuşunun dışarıdan başka bir yere sızmaması, sadece sürücü seviyesinde olması gerekiyordu. Ve bu geçici anahtarı ve bazı donanım bağlantısıyla ilgili verileri depolamak için özel alanlar kullandım . Böylece hiçbir türev yalnızca ortak bir arayüzü değil, bazılarını da korumalı kullanabildi.Bir görev için yaptığım "kullanışlı" alt yordamlar, ancak tuşlar ve HW etkileşimi ile bir kasa açamadım. Mantıklı?


üzgünüm beyler! sadece onları berbat ettim - cevabımı güncelleme =) TEŞEKKÜRLER! Acelem vardı ve yanlış
yazılmış

2
OP'nin iki koruma seviyesi arasındaki farkların farkında olduğunu düşünüyorum, ancak neden birinin diğerinin üzerinde kullanılması gerektiği ile ilgileniyor.
Sam,

@Sam, lütfen cevabımı daha derinden oku. Bunlar tamamen farklı alanın tipleri! Sadece Ortak özellikleri şey ikisi de kamuya referans edilemez olduğunu
Alexey Vesnin

2
Ne demek istediğinden emin değilim. Özel ve korunan arasındaki farkların farkındayım. Belki de koruma düzeyleriyle ne demek istediğimi yanlış anladınız? Erişim seviyesinden bahsediyorum. Cevabınız kötü olmasa da soruyu doğrudan ele almadığını belirtmeye çalışıyordum. OP, korumalı / özel / halkın ne anlama geldiğini biliyor gibi görünüyor, ancak hangi şartlar altında birini seçmek istediğinden emin değil. Bu sizin oy kullanmanızın bir yolu olabilir (benim tarafımdan değil).
Sam

@Sam Sanırım amacını anladım - benim gerçek pratik / deneyimden pratik bir vaka ekledi. Amacında eksik olan bu mu?
Alexey Vesnin, 13.03.2015
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.