Özel / iç sınıfı ne zaman kullanmalısınız?


21

Açıklığa kavuşturmak için, sorduğum şey

public class A{
    private/*or public*/ B b;
}

vs.

public class A{
    private/*or public*/ class B{
        ....
    }
}

Birini veya diğerini kullanmanın bazı nedenlerini kesinlikle düşünebilirim, ama gerçekten görmek istediğim şey, artı ve eksilerin sadece akademik olmadığını gösteren inandırıcı örnekler.


2
Cevap dil ​​ve çekirdek kütüphanelerin sağladığı olanaklara bağlı olacaktır. C # dili varsayarsak, bunları StyleCop ile çalıştırmayı deneyin. Bu sınıfı kendi dosyasına ayırma konusunda bir uyarı alacağınızdan eminim. Bu, MSFT'deki yeterli sayıda kişinin kullandığınız örneklerden birini kullanmanız gerekmediğini düşündüğü anlamına gelir.
İş

Akademik örnekler yeterince iyi değilse ikna edici bir örnek ne olurdu?

@ İş StyleCop yalnızca iç sınıflar dışarıdan görülebiliyorsa uyarı verir. Özel ise, tamamen tamam ve aslında birçok kullanım alanı var.
julealgon

Yanıtlar:


20

Genellikle bir sınıf, dış arabiriminin bir parçası olmaktan ziyade başka bir sınıfın bir iç uygulama ayrıntısı olduğunda kullanılır. Bunları çoğunlukla, dahili veri yapılarını c-tarzı yapılar için ayrı bir sözdizimi olmayan dillerde temiz yapan yalnızca veri sınıfları olarak gördüm. Ayrıca bazen olay işleyicileri veya çalışan iş parçacıkları gibi yüksek düzeyde özelleştirilmiş, tek yöntemden türetilmiş nesneler için de yararlıdır.


2
Onları bu şekilde kullanıyorum. Bir sınıf, işlevsel bir bakış açısından, başka bir sınıfın özel uygulama detayından başka bir şey değilse, tıpkı özel bir yöntem veya alan gibi, bu şekilde beyan edilmelidir. İsim alanını asla başka bir yerde kullanılmayacak çöplerle kirletmek için bir neden yok.
Aaronaught

9

Bir ağaç, liste, grafik vb. Oluşturduğunuzu varsayalım. Bir düğümün veya hücrenin iç ayrıntılarını neden dış dünyaya göstermelisiniz?

Bir grafik veya liste kullanan herkes, onun uygulamasına değil, yalnızca arayüzüne güvenmelidir, çünkü ileride bir gün (örneğin, dizi tabanlı bir uygulamadan işaretçi tabanlı bir uygulamaya) değiştirmek isteyebilirsiniz. veri yapısı ( her biri ) yeni uygulamaya uygun hale getirmek için kodlarını değiştirmelidir.

Bunun yerine, özel bir iç sınıfta bir düğümün veya hücrenin uygulanmasını kapsüllemek, istemcilerin veri yapınızın arabirimi kaldığı sürece sonuç olarak kodlarını ayarlamak zorunda kalmadan, uygulamayı istediğiniz zaman değiştirme özgürlüğü verir. bakir.

Veri yapınızın uygulamasının ayrıntılarını gizlemek de güvenlik avantajlarına yol açar, çünkü sınıfınızı dağıtmak istiyorsanız yalnızca derlenmiş uygulama dosyasıyla birlikte arabirim dosyasını hazırlayacaksınız ve kimse gerçekten dizileri mi yoksa işaretçileri mi kullandığınızı bilemeyecek böylece uygulamanızı bir tür sömürüden veya en azından kodunuzu yanlış kullanmanın veya denetlemenin imkansızlığından dolayı koruyun. Pratik konulara ek olarak, bu gibi durumlarda son derece zarif bir çözüm olduğu gerçeğini küçümsemeyin.


5

Bence , belirli bir göreve izin vermek için bir sınıfta kısaca kullanılan sınıflar için dahili olarak tanımlanmış sınıfları kullanmak adil bir polistir .

Örneğin, ilgisiz iki sınıftan oluşan bir veri listesini bağlamanız gerekiyorsa:

public class UiLayer
{
    public BindLists(List<A> as, List<B> bs)
    {
        var list = as.ZipWith(bs, (x, y) => new LayerListItem { AnA = x, AB = y});
        // do stuff with your new list.
    }

    private class LayerListItem
    {
        public A AnA;
        public B AB;
    }
}

Dahili sınıfınız başka bir sınıf tarafından kullanılıyorsa, ayrı bir sınıf koymalısınız. Dahili sınıfınız herhangi bir mantık içeriyorsa, onu ayırmanız gerekir.

Temel olarak, veri nesnelerinize delik takmak için harika olduklarını düşünüyorum, ancak gerçekten mantık içermeleri gerekiyorsa bakımı zordur, çünkü değiştirmeniz gerektiğinde onları nerede arayacağınızı bilmeniz gerekir.


2
C # varsayarsak, burada tuples kullanamaz mısınız?
İş

3
@ İş Tabii, ama bazen tuple.ItemXkodu belirsizleştirir.
Lasse Espeholt

2
@ Evet, lasseespeholt bunu doğru yaptı. {String Title; dize Açıklama; } bir Tuple <string, string> yerine.
Ed James

o noktada bu sınıfı kendi dosyasına koymak mantıklı değil miydi?
İş

Hayır, üst sınıfın görevinin dışına çıkmayan bir görevi başarmak için bazı verileri kısaca birleştirmek için gerçekten kullanmıyorsanız değil. En azından benim görüşüme göre değil!
Ed James

4
  • Bazı dillerdeki (örneğin Java) iç sınıflar, içerdiği sınıftaki bir nesneye bağlanır ve üyelerini nitelendirmeden kullanabilir. Mevcut olduğunda, diğer dil olanaklarını kullanarak bunları yeniden uygulamaktan daha açıktır.

  • Başka bir dilde iç içe sınıfların (örneğin C ++) böyle bir bağı yoktur. Sadece sınıf tarafından sağlanan kapsam belirleme ve erişilebilirlik denetimini kullanıyorsunuz.


3
Aslında Java bunların her ikisine de sahiptir .
Joachim Sauer

3

Java'da iç sınıflardan kaçınırım, çünkü çalışırken değiştirme iç sınıfların varlığında çalışmaz. Bundan nefret ediyorum, çünkü bu tür düşünceler için koddan ödün vermekten gerçekten nefret ediyorum, ancak bu Tomcat yeniden başlıyor.


bu konu bir yerde belgelendi mi?
gnat

Downvoter: iddiam yanlış mı?
kevin cline

1
Yanlış yorumladım çünkü cevabınızın ayrıntıları eksik değil, yanlış olduğu için değil. Detayların olmaması iddianızı doğrulamayı zorlaştırıyor. Bu konuda daha fazla bilgi eklerseniz, muhtemelen oyunuza geri döneceğim, çünkü bilgileriniz oldukça ilginç görünüyor ve yararlı olabilir
gnat

1
@gnat: Biraz araştırma yaptım ve bu iyi bilinen bir gerçek gibi görünse de, Java HotSwap'in sınırlamaları hakkında kesin bir referans bulamadım.
kevin cline

Şüpheci'de değiliz.SE :) sadece bazı referanslar olurdu, kesin olması gerekmiyor
gnat

2

Özel statik iç sınıfın kullanımlarından biri de Memo kalıbıdır. Hatırlanması gereken tüm verileri özel sınıfa koyar ve bazı işlevlerden Object olarak döndürürsünüz. Dışarıdaki hiç kimse (yansıma, serileştirme, hafıza denetimi olmadan) içine bakamaz / değiştiremez, ancak sınıfınıza geri verebilir ve durumunu geri yükleyebilir.


2

Özel bir iç sınıf kullanmanın bir nedeni, kullandığınız bir API'nin belirli bir sınıftan kalıtım gerektirmesi olabilir, ancak o sınıfın bilgisini dış sınıfınızın kullanıcılarına vermek istemeyebilirsiniz. Örneğin:

// async_op.h -- someone else's api.
struct callback
{
    virtual ~callback(){}
    virtual void fire() = 0;
};

void do_my_async_op(callback *p);



// caller.cpp -- my api
class caller
{
private :
    struct caller_inner : callback
    {
        caller_inner(caller &self) : self_(self) {}
        void fire() { self_.do_callback(); }
        caller &self_;
    };

    void do_callback()
    {
        // Real callback
    }

    caller_inner inner_;

public :
    caller() : inner_(*this) {}

    void do_op()
    {
        do_my_async_op(&inner_);
    }
};

Burada, do_my_async_op, kendisine geri çağrı türünde bir nesnenin geçirilmesini gerektirir. Bu geri aramanın API'nın kullandığı bir genel üye işlevi imzası var.

Outer_class öğesinden do_op () çağrıldığında, kendisine bir işaretçi yerine gerekli geri arama sınıfından miras alan özel iç sınıf örneğini kullanır. Dış sınıf, geri çağrıyı dış sınıfın özel do_callback üye işlevine dönüştürmek amacıyla dış sınıfa bir başvuruya sahiptir.

Bunun yararı, hiç kimsenin halka açık "fire ()" üye işlevini çağıramayacağından emin olmanızdır.



1

Özel ve iç sınıflar, kapsülleme düzeylerini artırmak ve uygulama ayrıntılarını gizlemek için kullanılır.

C ++ 'da, özel bir sınıfa ek olarak, aynı kavram bir sınıf cpp's anonim ad alanı uygulanarak elde edilebilir. Bu, bir uygulama ayrıntısını gizlemek / özelleştirmek için güzel bir hizmettir.

Bir iç veya özel sınıfla aynı fikirdir, ancak dosyanın derleme birimi dışında tamamen görünmez olduğu için daha da büyük bir kapsülleme düzeyinde. Üstbilgi dosyasında hiçbir şey görünmüyor veya sınıfın bildiriminde dışarıdan görülemiyor.


-1 ile ilgili yapıcı geri bildirim var mı?
hiwaylon

1
Oy vermedim ama soruyu gerçekten cevaplamadığınızı tahmin ediyorum: özel / iç sınıfı kullanmak için herhangi bir neden vermiyorsunuz. Sadece nasıl çalıştığını ve c ++ 'da benzer bir şeyin nasıl yapılacağını
açıklıyorsunuz

Aslında. Benim ve diğer cevapların (uygulama ayrıntılarını gizleme, kapsülleme düzeylerinin artması vb.) Açık olduğunu düşündüm, ancak bazılarını açıklığa kavuşturmaya çalışacağım. Teşekkürler @Simon.
hiwaylon

1
Güzel düzenleme. Ve lütfen bu tür bir tepki yüzünden rahatsız etmeyin. SO ağı, sinyal / gürültü oranını iyileştirmek için politikalar uygulamaya çalışıyor. Bazı insanlar soru / cevap kapsamı konusunda oldukça katıdır ve bazen iyi olmayı unuturlar (örneğin kendi downvotelarını yorumlayarak)
Simon Bergot

@Simon Teşekkürler. Kötü iletişim kalitesi nedeniyle hayal kırıklığı yaratıyor. Belki web anonim peçe arkasında "katı" olmak biraz fazla kolay? Sanırım yeni bir şey yok. Olumlu geribildirim için tekrar teşekkürler.
hiwaylon
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.