Java'da, korunan üyeler neden aynı paketin sınıfları tarafından erişilebilir hale getirildi?


14

Resmi belgelerden ...

Değiştirici Sınıf Paketi Alt Sınıf Dünyası 
kamu YYYY 
korumalı YYYN 
değiştirici yok YYNN 
özel YNNN 

Mesele şu ki, aynı paketteki bir sınıftan korunan üyelere erişmem gereken bir kullanım senaryosu olduğunu hatırlayamıyorum.

Bu uygulamanın arkasındaki nedenler nelerdi?

Düzenleme: Açıklığa kavuşturmak için, hem bir alt sınıfın hem de aynı paket içindeki bir sınıfın korumalı bir alana veya yönteme erişmesi gereken belirli bir kullanım durumu arıyorum.

package some.package;
public class A {
 protected void protectedMethod(){
  // do something
 }
}

package another.package;
public class B extends A{
 public void someMethod(){
  // accessible because B is a subclass of A
  protectedMethod();
 }
} 

package some.package;
public class C {
 public void anotherMethod(){
  // accessible because C is in the same package as A
  protectedMehtod();
 }
}

Yanıtlar:


4

aynı paket içindeki hem bir alt sınıfın hem de bir sınıfın korunan bir alana veya yönteme erişmek için ihtiyaç duyduğu belirli bir kullanım durumu arıyorsunuz ...

Bana göre, böyle bir kullanım örneği spesifik olmaktan ziyade geneldir ve tercihlerimden kaynaklanıyor:

  1. Mümkün olduğunca katı erişim değiştiriciyle başlayın, yalnızca daha sonra gerekli görüldüğü gibi daha zayıf olanlara başvurun.
  2. Birim testlerinin, test edilen kodla aynı pakette bulunmasını sağlayın.

Yukarıdan, varsayılan erişim değiştiricileri ile nesnelerim için tasarlamaya başlayabilirim (ile başlayacağım, privateancak bu birim testini zorlaştıracaktır):

public class Example {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        void doSomething() {} // default access
    }
    static class Unit2 {
        void doSomething() {} // default access
    }

    static class UnitTest {
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

Yan not Yukarıdaki parçada Unit1, Unit2ve UnitTestvardır yuvalanmış dahilinde Examplesunum basitlik için, ama gerçek bir projede, ben büyük olasılıkla ayrı dosyalarda (ve bu sınıflar olurdu UnitTestbile ayrı bir dizinde ).

Sonra, bir zorunluluk ortaya çıktığında, erişim denetimini varsayılandan zayıflatabilirim protected:

public class ExampleEvolved {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        protected void doSomething() {} // made protected
    }
    static class Unit2 {
        protected void doSomething() {} // made protected
    }

    static class UnitTest {
        // ---> no changes needed although UnitTest doesn't subclass
        // ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

Gördüğünüz gibi, ExampleEvolvednesneye erişim bir alt sınıf olmasa da, aynı paketten korunan yöntemlerin erişilebilir olması nedeniyle birim test kodunu değiştirmeden tutabilirim .

Daha az değişiklik gerekli => daha güvenli değişiklik; Sonuçta sadece erişim değiştiricileri değiştirdim ve hangi yöntemleri değiştirmedim Unit1.doSomething()ve Unit2.doSomething()yapmadım, bu yüzden birim test kodunun değişiklik yapmadan çalışmaya devam etmesini beklemek doğaldır.


5

Bunun iki kısmı olduğunu söyleyebilirim:

  1. Varsayılan "paket" erişimi, sınıflar her zaman iyi bir kapsülleme birimi olmadığından çok çeşitli durumlarda kullanışlıdır. Bazı nesnelerin diğer nesnelerin toplanması gibi davrandığı çeşitli bileşik nesneler, ancak tüm koleksiyonda bazı değişmezler olduğu için öğelerin herkes tarafından değiştirilemez olması gerekir, bu nedenle koleksiyonun öğelere daha yüksek erişime sahip olması gerekir. C ++ 'nin arkadaşları, Java'nın paket erişimi vardır.
  2. Şimdi "paket" erişim kapsamı temel olarak "alt sınıf" (korumalı) kapsamından bağımsızdır. Bu nedenle, yalnızca paket, yalnızca alt sınıflar ve paket ve alt sınıflar için ek erişim belirteçlerine ihtiyacınız olacaktır. "Paket" kapsamı, bir paketteki sınıflar kümesi genellikle belirlendiğinden, bir alt sınıf herhangi bir yerde görünebileceğinden daha kısıtlıdır. İşleri basit tutmak için Java, paket erişimini korumalı erişime dahil eder ve alt sınıflar için değil, paket için ekstra tanımlayıcıya sahip değildir. Gerçi neredeyse her zaman protectedtam olarak bunu düşünmelisin .

protectedYalnızca alt sınıf olması daha kolay olmaz mıydı ? Dürüst olmak gerekirse, uzun bir süre boyunca, bu davranış olduğu izlenimi altındaydım
jramoyo

@jramoyo: Hayır, çünkü yine de birleşik davranışı bir şekilde kullanılabilir hale getirmeniz gerekir, bu da başka bir belirteç anlamına gelir.
Jan Hudec

6
@jramoyo - C # 'da, protectedsadece sınıf ve alt sınıftır ve internalkütüphane / paket geniştir. Ayrıca protected internalJava ile eşdeğer olan vardır protected.
Bobson

@Bobson - teşekkürler, C # uygulaması daha iyi bir seçim gibi görünüyor
jramoyo

5

IMHO, bu Java için kötü bir tasarım kararıydı.

Sadece spekülasyon yapıyorum, ancak erişim seviyelerinin katı bir ilerleme içinde olmasını istediklerini düşünüyorum: özel - "paket" - korumalı - kamu. Bazı alanların pakette kullanılabileceği, ancak alt sınıfların bulunmadığı, bazılarının alt sınıfların kullanabileceği, ancak paketin bulunmadığı ve bazılarının olduğu bir hiyerarşiye sahip olmak istemiyorlardı.

Yine de, alçakgönüllü görüşüme göre, başka bir yoldan gitmiş olmalılar: Korumalıların sadece sınıf ve alt sınıflar tarafından görülebildiğini ve bu paketin sınıf, alt sınıflar ve paket tarafından görülebildiğini söyledi.

Sıklıkla bir sınıfta alt sınıfların erişebilmesi gereken verilerim var, ancak paketin geri kalanında değil. Tersinin doğru olduğu bir davayı düşünmek için zorlandım. Verileri paylaşması gereken, ancak bu verileri paketin dışından güvende tutması gereken birbiriyle ilişkili sınıflardan oluşan bir paket yaşadım. Tamam, onları bir pakete koyun, vb. Ama paketin veri paylaşmasını istediğim bir durumum olmadı, ancak alt sınıflardan uzak tutmak istiyorum. Tamam, durumun ortaya çıktığını hayal edebiliyorum. Sanırım bu paket, hakkında hiçbir şey bilmediğim sınıflar tarafından genişletilebilecek bir kütüphanenin parçasıysa, aynı nedenlerle bir sınıftaki verileri özel hale getireceğim. Ancak verileri yalnızca sınıf ve çocukları için kullanılabilir hale getirmek istemek çok daha yaygındır.

Çocuklarımla aramda gizli tuttuğum birçok şey var ve komşularımızla paylaşmıyoruz. Komşularla aramda gizli kaldığım ve çocuklarımla paylaşmadığım çok az şey var. :-)


0

Hemen akla gelen iyi bir örnek, pakette çok kullanılan yardımcı program sınıflarıdır, ancak genel erişim istemezsiniz (sahne arkası-görüntü-yükleme-diskten yükleme, tanıtıcı oluşturma / imha sınıfları, vb.) .) yerine her şeyi [Java'nın eşdeğer yapma friend access modifier or idiomiçinde C++her sınıf her şeyin] otomatik olarak kullanılabilir.


1
Fayda sınıfları, üyeleri yerine bütün olarak iç sınıflara bir örnektir.
Jan Hudec

0

Korumalı / paket erişim değiştiricisinin kullanım örnekleri , C ++ 'da arkadaş erişim değiştiricilerininkine benzer .

Bir kullanım örneği Memento modelini uygularken .

Memento nesnesinin, geri alma işlemleri için bir kontrol noktası olarak kullanılabilmesi için bir nesnenin iç durumuna erişmesi gerekir.

Sınıfın aynı pakette bildirilmesi, Java'nın "arkadaş" erişim değiştiricisi olmadığından Memento desenini elde etmenin olası yollarından biridir .


1
Hayır, hatıra nesnesine ihtiyaç yoktur ve nesneye erişimi olmamalıdır. Kendisini hatıra haline getiren ve tekrar serileştiren nesnedir. Ve hatıra kendisi sadece aptal bir çanta. Her ikisinin de diğerine kamu erişiminden fazlası olmamalıdır.
Jan Hudec

@JanHudec Kelimenin tam anlamıyla "Memento modelini elde etmenin olası yollarından biri -> bir <-" dir .
Tulains Córdova

Memento modeline ulaşmanın bir başka olası yolu da her şeyi halka açık hale getirmektir. Yani, fikrini göremiyorum.
Thomas Eding

-1

simetri?

Bu tür bir erişime ihtiyaç duyulması nadirdir, bu nedenle varsayılan erişim çok nadir kullanılır. Ancak bazen çerçeveler, sarmalayıcı sınıflarının doğrudan sınıflarınızla etkileşime giren aynı pakete yerleştirildiği, performans nedenleriyle erişimcilere değil üyelere giderek oluşturulan kod için bunu ister. GWT'yi düşünün.


1
teşekkürler, bir örnek var mı? sesler "korumalı" yerine "varsayılan" bir erişimci tarafından gerçekleştirilebilir
jramoyo

-1

Java'nın kapsülleme hiyerarşisi iyi tanımlanmıştır:

Sınıf -> Paket -> Kalıtım

"Korumalı", Java tasarımcıları tarafından kararlaştırıldığı üzere paket varsayılanından daha zayıf bir gizlilik biçimidir. Paket varsayılan öğelerine erişim, korumalı öğelere erişmesine izin verilen varlıkların bir alt kümesiyle sınırlıdır.

İç içe geçecek şeylere erişmesine izin verilen varlık kümelerinizin olması, matematiksel ve uygulama açısından çok mantıklıdır. (Sınıfların diğer paketlerden devralmasına izin verildiğinden, paket erişim kümenizi korumalı erişim kümenizin içine yerleştiremezsiniz).

Java.util'de bir şeyin alt sınıfta olan com.example.foo.bar'daki bir sınıftan başka bir sınıfla "daha dostça" olması kavramsal bir bakış açısından mantıklıdır. İlk durumda, sınıfların aynı yazar veya en azından aynı kuruluştan gelen kodlayıcılar tarafından yazılması muhtemeldir.


1
"daha zayıf bir form ..." ne anlama geliyor ?
gnat
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.