Kapsülleme hala OOP'un üzerinde durduğu fillerden biri mi?


97

Kapsülleme, alanların tümünü veya hemen hemen tamamını özel hale getirmemi ve bunları alıcılar / belirleyiciler tarafından ortaya çıkarmamı söyler. Ancak, Lombok gibi kütüphaneler artık tüm özel alanları kısa bir açıklama ile göstermemize izin veriyor @Data. Tüm özel alanlar için alıcılar, ayarlayıcılar ve ayar yapıcıları yaratacaktır.

Biri bana tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın ne demek olduğunu açıklayabilir mi? O zaman neden sadece ortak alanları kullanmıyoruz? Sadece başlangıç ​​noktasına dönmek için uzun ve zor bir yol yürüdüğümüzü hissediyorum.

Evet, alıcılar ve belirleyiciler aracılığıyla çalışan başka teknolojiler var. Ve bunları basit ortak alanlarda kullanamayız. Ancak bu teknolojiler sadece kamuoyunun alıcılarının / belirleyicilerinin ardındaki özel alanların olduğu özel mülklere sahip olduğumuz için ortaya çıktı . Bu özelliklere sahip olmasaydık, bu teknolojiler başka bir yol geliştirirdi ve ortak alanları desteklerdi. Ve her şey basit olacak ve şimdi Lombok'a ihtiyacımız olmayacaktı.

Bütün bu döngünün anlamı nedir? Ve şimdi kapsülleme gerçek hayattaki programlamada gerçekten herhangi bir anlama sahip mi?


19
"It will create getters, setters and setting constructors for all private fields."- Bu aracı tanımladığınız gibi , kapsülleme koruyor gibi geliyor . (En azından gevşek, otomatik, biraz anemik model anlamında). Sorun tam olarak nedir?
David,

78
Kapsülleme, nesnenin uygulama içindekilerini genel sözleşmesinin (genellikle bir arayüz) arkasına saklıyor. Alıcılar ve ayarlayıcılar tam tersi bir şey yapar - nesnenin içindekileri ortaya çıkarırlar, bu yüzden sorun kapsülleme değil alıcılar / ayarlayıcılardır.

22
@VinceEmigh veri sınıflarının enkapsülasyonu yoktur . Bunların örnekleri tam olarak ilkellerin olduğu anlamdaki değerlerdir
Caleth

10
@ JavaBeans kullanarak VinceEmigh OO değil, Prosedürel . Edebiyatın onlara “Nesneler” dediği tarihin bir yanılgısıdır.
Caleth

28
Bu konuya yıllar içinde çok düşündüm; OOP'nin amacının uygulamadan farklı olduğu bir durum olduğunu düşünüyorum. Smalltalk okuduktan sonra o ne cepten en kapsülleme açık amaçlanan olmak (yani paylaşılan protokolü gibi yöntemlerle bağımsız bilgisayar gibi olmak her sınıf,) bana şu ana kadar bilinmeyen nedenlerle, kesinlikle bu hale getirmek için popülaritesi yakalandı olmasına rağmen, Kavramsal enkapsülasyon sağlamayan getter / setter nesneleri (hiçbir şeyi gizlemezler, hiçbir şeyi yönetmezler ve verilerden başka hiçbir sorumluluğu yoktur) ve yine de hala özellikleri kullanırlar.
jrh

Yanıtlar:


82

Tüm niteliklerinizi alıcılar / ayarlayıcılar ile gösterirseniz, hala C veya başka herhangi bir prosedürel dilde kullanılan veri yapısını kazanıyorsunuzdur. O edilir değil kapsülleme ve Lombok sadece prosedürel kod daha az acı ile çalışmak yapıyor. Alıcılar / belirleyiciler, kamusal alanlar kadar kötü. Gerçekten fark yok.

Ve veri yapısı bir nesne değildir. Bir arayüz yazarak bir nesne oluşturmaya başlayacaksanız, arayüze alıcı / ayarlayıcıları asla ekleyemezsiniz. Niteliklerinizi göstermek, verilerle yapılan manipülasyonun bir nesnenin dışında olduğu ve kod tabanının her yerine yayıldığı spagetti prosedür koduna yol açar. Artık nesnelerle konuşmak yerine verilerle ve verilerle manipülasyonlarla uğraşıyorsunuz. Alıcılarla / ayarlayıcılarla, bununla işlem yapılmasının düz zorunluluk biçiminde yapıldığı veri odaklı prosedürel programlamaya sahip olacaksınız. Veri al - bir şeyler yap - veriyi ayarla.

OOP'de kapsülleme doğru şekilde yapılırsa bir fildir. Durum ve uygulama ayrıntılarını kapsamaya devam etmelisiniz ki böylelikle nesne üzerinde tam kontrol sahibi olacaksınız. Mantık nesnenin içine odaklanacak ve kod tabanının tamamına yayılmayacak. Ve evet - kod daha sürdürülebileceğinden, kapsülleme programlamada hala önemlidir.

DÜZENLEMELER

Devam eden tartışmaları gördükten sonra birkaç şey eklemek istiyorum:

  • Alıcıların / ayarlayıcıların özelliklerinden kaç tanesini kullandığın ve bunu ne kadar dikkatle yaptığınız önemli değil. Daha seçici olmak, kodunuzda kapsülleme bulunan OOP kodunu yapmaz. Açığa çıkardığınız her özellik, zorunlu çıplak prosedürle bu çıplak verilerle çalışan bir prosedürle sonuçlanacaktır. Daha seçici olmakla birlikte kodunuzu daha az yayarsınız. Bu çekirdeği değiştirmiyor.
  • Evet, sistem içindeki sınırlarda diğer sistemlerden veya veritabanlarından çıplak veriler elde edersiniz. Ancak bu veri sadece başka bir kapsülleme noktasıdır.
  • Nesneler güvenilir olmalıdır . Nesnelerin bütün fikri sorumludur, bu nedenle düz ve zorunlu emirler vermenize gerek yoktur . Bunun yerine, bir nesneyi sözleşme yoluyla iyi yaptığı şeyi yapmasını istersiniz . Güvenle kısmını hareket temsilci için nesne. Nesneler encapsulate devlet ve uygulama detaylarını.

Öyleyse soruya geri dönersek, neden bunu yapmalıyız. Bu basit örneği düşünün:

public class Document {
    private String title;

    public String getTitle() {
        return title;
    }
}

public class SomeDocumentServiceOrHandler {

    public void printDocument(Document document) {
        System.out.println("Title is " + document.getTitle());
    }
}

Burada, iç detayı alıcı tarafından açığa çıkaran Belge ve nesnenin dışındakilerle çalışan fonksiyonunda dış prosedür koduna sahibiz . Bu neden kötü? Çünkü şimdi sadece C stil koduna sahipsiniz. Evet yapılandırılmış, ancak gerçekten fark nedir? C fonksiyonlarını farklı dosyalarda ve isimlerle yapılandırabilirsiniz. Ve sözde katmanlar tam olarak bunu yapıyor. Servis sınıfı sadece verilerle çalışan bir grup prosedürdür. Bu kod daha az bakım gerektiriyor ve birçok sakıncası var.printDocument

public interface Printable {
    void print();
}

public final class PrintableDocument implements Printable {
    private final String title;

    public PrintableDocument(String title) {
        this.title = title;
    }

    @Override
    public void print() {
        System.out.println("Title is " + title);
    }
}

Bununla karşılaştırın. Şimdi bir sözleşmemiz var ve bu sözleşmenin uygulama detayları nesnenin içinde gizli . Artık bu sınıfı gerçekten test edebilirsiniz ve bu sınıf bazı verileri içine alıyor. Bu verilerle nasıl çalıştığı bir nesne sorunudur. Artık nesneyle konuşmak için ondan kendini basmasını istemeniz gerekiyor . Bu kapsülleme ve bu bir nesne. OOP ile bağımlılık enjeksiyonunun, alay etmenin, test etmenin, tek sorumlulukların ve bir çok avantajın tam gücüne sahip olacaksınız.


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
maple_shaft

1
"Alıcılar / belirleyiciler, kamusal alanlar kadar kötü" - bu doğru değil, en azından birçok dilde. Genelde düz alan erişimini geçersiz kılamazsınız, ancak alıcıları / ayarlayıcıları geçersiz kılabilirsiniz. Bu çocuk sınıflarına çok yönlülük verir. Ayrıca sınıfların davranışını değiştirmeyi de kolaylaştırır. örneğin, özel bir alan tarafından desteklenen bir alıcı / ayarlayıcı ile başlayabilir ve daha sonra farklı bir alana geçebilir veya değeri diğer değerlerden hesaplayabilirsiniz. Düz alanlar ile de yapılamaz. Bazı diller, alanların esasen otomatik alıcı ve ayarlayıcılara sahip olmasına izin verir, ancak Java böyle bir dil değildir.
Kat

Eh, hala ikna olmadı. Örneğiniz tamam ama sadece "doğru olanı" değil, farklı bir kodlama stilini gösteriyor. Bugünlerde çoğu dilde çok paradigma olduğunu ve nadiren saf OO ou saf usule ilişkin olduğunu unutmayın. Kendini "saf OO konseptlerine" zorlamak. Örnek olarak - örneğinizde DI kullanamazsınız çünkü baskı mantığını bir alt sınıfa bağladınız. Yazdırma bir belgenin parçası olmamalıdır - yazdırılabilir bir Belge yazdırılabilir kısmını (alıcı aracılığıyla) bir Yazıcı Hizmetine maruz bırakacaktır.
T. Sar,

Buna uygun bir OO yaklaşımı, "Saf OO" yaklaşımına gideceksek, bir GetPrintablePart türünü kullanarak, cehennemde ne basılması gerektiğini soran bir mesajla soyut bir Yazıcı Hizmeti sınıfını uygulayan bir şey kullanırdı. Yazıcı Hizmetini uygulayan şey herhangi bir tür yazıcı olabilir - bir PDF'ye, ekrana, TXT'ye yazdırın ... Çözümünüz, yazdırma mantığını başka bir şeyle değiştirmeyi imkansız hale getirir, daha fazla bağlanabilir ve daha az bakım yapılabilir "yanlış" örneğinden daha fazla.
T. Sar,

Sonuç olarak: Getters and Setters kötü ya da OOP'u bozmaz - Onları nasıl kullanacaklarını anlamayan insanlar. Örnek olay, DI'nin nasıl çalıştığını tüm noktayı kaybeden insanlara yönelik bir ders kitabı örneğidir. "Düzeltilen" örnek zaten DI-etkin, ayrıştırılmış, kolayca alay edilebiliyordu ... Gerçekten - "Mirasa Göre Kompozisyonu Tercih Et" özelliğini hatırlıyor musun? OO sütunlarından biri mi? Kodu tekrar kırdığın zaman pencereden fırlattın. Bu herhangi bir ciddi kod incelemesinde uçmazdı.
T. Sar,

76

Biri bana açıklayabilir mi, tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın anlamı nedir? Neden sadece ortak alanları kullanmıyoruz?

Anlam şu ki bunu yapmamanız gerekiyor .

Kapsülleme, yalnızca erişmek için gerçekten diğer sınıflara ihtiyaç duyduğunuz alanları ortaya çıkardığınız ve bu konuda çok seçici ve dikkatli olduğunuz anlamına gelir.

Do not sadece varsayılan başına tüm alanları Alıcılar ve ayarlayıcılar ver!

Bu, tamamen kamuoyuna açık alıcı ve belirleyiciler kavramının geldiği yer olan, ironik bir şekilde JavaBeans spesifikasyonunun ruhuna karşı.

Ancak spekere bakarsanız, alıcıların ve ayarlayıcıların yaratılmasının çok seçici olmasını istediğini ve "salt okunur" özellikler (belirleyici yok) ve "salt okunur" özellikler hakkında konuştuğunu görürsünüz (hayır gaz giderici).

Diğer bir faktör ise alıcıların ve ayarlayıcıların özel alana basit bir şekilde erişmeleri gerekmiyor . Alıcı, isteğe bağlı olarak karmaşık bir şekilde döndürdüğü değeri hesaplayabilir, belki önbelleğe alabilir. Bir ayarlayıcı değeri doğrulayabilir veya dinleyicileri haberdar edebilir.

Öyleyse işte buradasınız : kapsülleme, yalnızca gerçekten göstermeniz gereken işlevselliği ortaya çıkarmanız anlamına gelir. Ancak, neyi göstermeniz gerektiğini düşünmüyorsanız ve sadece nilly-nilly, bazı sözdizimsel dönüşümü izleyerek her şeyi ortaya çıkarın, o zaman elbette bu gerçekten kapsülleme değildir.


20
“[G] etterler ve ayarlayıcılar mutlaka basit bir erişim değil” - Bence bu bir kilit nokta. Kodunuz bir alana ada göre erişiyorsa, davranışı daha sonra değiştiremezsiniz. Obj.get () kullanıyorsanız, yapabilirsiniz.
Dan Ambrogio

4
@jrh: Java'da kötü bir uygulama olduğunu hiç duymadım ve oldukça yaygın.
Michael Borgwardt

2
@ MichaelBorgwardt İlginç; biraz konu dışı ama her zaman Microsoft'un neden C # için bunu yapmasını önerdiğini merak ettim. Sanırım bu kurallar, C # 'da ayarlayıcıların kullanabileceği tek şey, dahili olarak kullanılan bir değeri, başarısız olamayacak veya geçersiz bir değere sahip olacak şekilde (örneğin bir PositionInches özelliğine ve bir PositionCentimeters özelliğine sahip olmak üzere) verilen bir değeri dönüştürmek olduğunu ima ediyor. otomatik olarak içten mm'ye dönüştürür nerede)? Harika bir örnek değil, şu anda bulabileceğim en iyisi bu.
jrh

2
Jrh bu kaynak, ayarlayıcıların aksine, alıcılar için yapmadığını söylüyor.
Kaptan Adam

3
@ Gangnus ve gerçekten birisinin alıcı / ayarlayıcı içinde bir mantık sakladığını görüyor musunuz? O kadar alıştık ki getFieldName(), bizim için otomatik bir sözleşme haline geldi. Bunun arkasında bazı karmaşık davranışlar beklemeyeceğiz. Çoğu durumda sadece kapsülleme düz kırılır.
Izbassar Tolegen

17

Sanırım konunun özü yorumunuzla açıklanıyor:

Düşüncene tamamen katılıyorum. Fakat bir yerlerde veri içeren nesneler yüklemeliyiz. Örneğin, XML'den. Ve bunu destekleyen mevcut platformlar bunu alıcılar / belirleyiciler aracılığıyla yapar, böylece kodumuzun kalitesini ve düşünme biçimimizi düşürür. Lombok, aslında, kendi başına kötü değil, ama varlığı çok kötü bir şeyimiz olduğunu gösteriyor.

Sahip olduğunuz problem kalıcılık veri modelini aktif veri modeliyle karıştırmanızdır .

Bir uygulama genellikle birden fazla veri modeline sahip olacaktır :

  • Veritabanıyla konuşmak için bir veri modeli,
  • yapılandırma dosyasını okumak için bir veri modeli,
  • başka bir uygulamayla konuşmak için bir veri modeli,
  • ...

datamodel'in tepesinde aslında hesaplamalarını yapmak için kullanır.

Genel olarak, dış ile iletişim için kullanılan veri modülleri izole edilmeli ve üzerinde hesaplamaların yapıldığı iç veri modelinden (iş nesne modeli, BOM) bağımsız olmalıdır :

  • bağımsız : böylece tüm istemcileri / sunucuları değiştirmek zorunda kalmadan gereksinimlerinize uygun olarak Malzeme Listesinde özellik ekleyebilir / kaldırabilirsiniz, ...
  • izole : böylece tüm hesaplamalar değişmezlerin yaşadığı BOM'da gerçekleştirilir ve bir hizmetten diğerine geçmek ya da bir hizmeti yükseltmek kod tabanı boyunca dalgalanmaya neden olmaz.

Bu senaryoda, iletişim katmanlarında kullanılan nesnelerin tüm öğelerin herkese açık veya alıcıların / ayarlayıcıların maruz kalması çok iyi. Bunlar hiçbir şekilde değişmeyen düz nesnelerdir.

Öte yandan, ürün listenizde genellikle çok sayıda belirleyici bulunmasını engelleyen değişmezler olmalıdır (alıcılar değişmezleri etkilemez, ancak kapsüllemeyi bir dereceye kadar azaltırlar).


3
İletişim nesneleri için alıcılar ve ayarlayıcılar yaratmazdım. Sadece tarlaları halka açıklardım. Neden yararlıdan daha fazla iş yaratın?
immibis

3
@ immibis: Genel olarak aynı fikirdeyim, ancak OP tarafından belirtildiği gibi bazı çerçeveler alıcılar / rampalar gerektiriyor, bu durumda sadece uymak zorundasınız. OP'nin bunları tek bir öznitelik uygulaması ile otomatik olarak yaratan bir kütüphane kullandığını ve bu nedenle onun için çok az çalıştığını unutmayın.
Matthieu M.

1
@Gangnus: Buradaki fikir, alıcıların / ayarlayıcıların, kirlenmenin normal olduğu, ancak uygulamanın geri kalanının (saf kod) kontamine olmadığı ve zarif kaldığı sınır (I / O) katmanına izole edilmiş olmasıdır.
Matthieu M.

2
@kubanczyk: resmi tanım bildiğim kadarıyla Business Object Model. Burada, uygulamanızın "saf" çekirdeğinde mantığı yürüttüğünüz veri modeli olan "iç veri modeli" dediğim şeye karşılık gelir.
Matthieu M.

1
Bu pratik yaklaşım. Melez bir dünyada yaşıyoruz. Dış kütüphaneler, malzeme listesi oluşturucularına hangi verileri ileteceğini bilseydi, o zaman sadece malzeme listesi elde ederdik.
Adrian Iftode 10:17

12

Aşağıdakileri göz önünde bulundur..

Özelliğe sahip bir Usersınıfınız var int age:

class User {
    int age;
}

Bunu büyütmek istersiniz, böylece Usersadece bir yaş yerine, doğum tarihi vardır. Bir alıcı kullanarak:

class User {
    private int age;

    public int getAge() {
        return age;
    }
}

int ageDaha karmaşık bir alan için alanı değiştirebiliriz LocalDate dateOfBirth:

class User {
    private LocalDate dateOfBirth;

    public int getAge() {
        LocalDate now = LocalDate.now();
        int year = ...; // calculate using dateOfBirth and now
        return year;
    }

    // other behaviors can now make use of dateOfBirth
}

Sözleşme ihlali yok, kod ihlali yok .. Daha karmaşık davranışlar için hazırlık aşamasında iç temsilleri ölçeklendirmekten başka bir şey yok.

Alanın kapsüllenir.


Şimdi, endişeleri gidermek için ..

Lombok'un @Dataek açıklaması Kotlin'in veri sınıflarına benzer .

Tüm sınıflar davranışsal nesneleri temsil etmez. Kapsülleme kırma gelince, bu özelliği kullanımınıza bağlıdır. Sen açığa edilmemelidir tüm alıcılar aracılığıyla alanları.

Kapsülleme, bir sınıf içindeki yapılandırılmış veri nesnesinin değerlerini veya durumunu gizlemek için kullanılır

Daha genel bir anlamda kapsülleme, bilgiyi gizleme eylemidir. Kötüye kullanırsanız @Data, muhtemelen enkapsülasyonu kırdığınızı varsaymak kolaydır. Ama bunun bir amacı olmadığını söylemek değil. JavaBeans, örneğin, bazıları tarafından kaşlarını çattı. Yine de işletme gelişiminde yoğun olarak kullanılıyor.

Fasulyenin kullanımı nedeniyle işletme gelişiminin kötü olduğu sonucuna varır mısın? Tabii ki değil! Gereksinimler standart geliştirmeden farklıdır. Fasulye kötüye kullanılabilir mi? Tabii ki! Her zaman kötüye kullanılırlar!

Lombok ayrıca desteklemekte @Getterve @Setterbağımsız olarak - gereksinimlerinizin gerektirdiği şeyi kullanın.


2
Bu, tasarımdaki tüm alanları kapsülleyen @Databir tür ek açıklamanın
kesilmesiyle ilgili değildir

1
Hayır, alanlar gizli değil . Çünkü her şey setAge(xyz)
yoluna girebilir

9
Alanları @Caleth olan gizli. Belirleyicilerin ön ve son koşullarına sahip olamıyormuş gibi davranıyorsunuz; bu, belirleyicileri kullanmak için çok yaygın bir kullanım örneğidir. Her ikisi de (C # gibi) desteklendiği gibi C # gibi dillerde bile bir alan == özelliği gibi davranıyorsunuz. Alan başka bir sınıfa taşınabilir, daha karmaşık bir temsil için değiştirilebilir ...
Vince Emigh

1
Ve demek istediğim bu önemli değil
Caleth

2
@Caleth Nasıl önemli değil? Bu hiç mantıklı değil. Sen çünkü kapsülleme geçerli değildir söylüyorsun sen o tanım gereği geçerlidir ve kullanım durumları var olsa bile, bu durumda önemli değil misin?
Vince Emigh

11

Kapsülleme, alanların tümünü veya hemen hemen tamamını özel hale getirmemi ve bunları alıcılar / belirleyiciler tarafından ortaya çıkarmamı söyler.

Nesne yönelimli programlamada kapsülleme böyle tanımlanmaz. Kapsülleme, her bir nesnenin, dış kabuğu (kamu api) iç kısmına (özel yöntemler ve alanlar) erişimi koruyan ve düzenleyen ve onu görünümden gizleyen bir kapsül gibi olması gerektiği anlamına gelir. Dahili olanları gizleyerek, arayanlar dahili olanlara bağlı kalmayacak, dahili olmayanların arayanları değiştirmeden (hatta yeniden derleyecek şekilde) değiştirmelerine olanak tanıyacaktır. Ayrıca, kapsülleme, yalnızca arayanlar için güvenli işlemler yaparak, her nesnenin kendi değişmezlerini zorlamasını sağlar.

Bu nedenle enkapsülasyon, her bir nesnenin içini gizlediği ve değişmezlerini uyguladığı özel bir bilgi gizleme olayıdır.

Tüm alanlar için alıcılar ve ayarlayıcılar üretmek, oldukça zayıf bir kapsülleme biçimidir, çünkü dahili verilerin yapısı gizli değildir ve değişmezler zorlanamaz. Ancak, arayanları değiştirmek zorunda kalmadan, verilerin dahili olarak saklanma biçimini (eski yapıya dönüştürebildiğiniz sürece) değiştirebilme avantajınız vardır.

Biri bana tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın ne demek olduğunu açıklayabilir mi? O zaman neden sadece ortak alanları kullanmıyoruz? Sadece başlangıç ​​noktasına dönmek için uzun ve zor bir yol yürüdüğümüzü hissediyorum.

Kısmen, bu tarihi bir kazadan kaynaklanıyor. İlk olarak, Java'da yöntem çağırma ifadelerinin ve alan erişim ifadelerinin çağrı sitesinde sözdizimsel olarak farklı olduğu, yani bir alan erişiminin bir alıcı veya ayarlayıcı çağrısı ile değiştirilmesinin bir sınıfın API'sini bozmasıdır. Bu nedenle, bir erişimciye ihtiyacınız varsa, şimdi bir tane yazmanız veya API'yi kırmanız gerekir. Dil düzeyinde özellik desteğinin olmaması, özellikle C # ve EcmaScript gibi diğer modern dillerle keskin bir tezat oluşturuyor .

Grev 2, JavaBeans spesifikasyonunun özellikleri alıcılar / ayarlayıcılar olarak tanımladığı, alanların özellik olmadığı şeklindedir. Sonuç olarak, çoğu erken kurumsal çerçeve alıcıları / ayarlayıcıları destekledi, ancak alanları desteklemedi. Geçmişte uzun zaman geçti ( Java Kalıcılık API'si (JPA) , Bean Doğrulama , XML Bağlama için Java Mimarisi (JAXB) , Jackson(şimdiye kadar tüm destek alanları gayet iyi), ancak eski dersler ve kitaplar oyalanmaya devam ediyor ve herkes işlerin değiştiğini bilmiyor. Dil seviyesi mülk desteğinin yokluğu bazı durumlarda hala acı verici olabilir (örneğin, JPA tembel tekil kuruluşların kamuya açık alanlar okunduğunda tetiklememesi nedeniyle), ancak genel olarak kamuya açık alanlar gayet iyi çalışıyor. Şüphesiz, şirketim tüm DTO'ları REST API'leri için ortak alanlarla yazıyor (sonuçta internet üzerinden iletilen herkese açık değil :-).

Bu Lombok en dedi @Datagetters / ayarlayıcıları üretmek daha fazlasını yapıyor: Aynı zamanda üretir toString(), hashCode()ve equals(Object)oldukça değerli olabilir ki.

Ve şimdi kapsülleme, gerçek hayattaki programlamada gerçekten bir anlam ifade ediyor mu?

Kapsülleme paha biçilmez veya tamamen yararsız olabilir, kapsüllenen nesneye bağlıdır. Genel olarak, sınıf içindeki mantık ne kadar karmaşıksa, kapsülleme yararı da o kadar büyük olur.

Her alan için otomatik olarak oluşturulan alıcılar ve ayarlayıcılar genellikle aşırı kullanılır, ancak eski çerçevelerle çalışmak veya alanlar için desteklenmeyen zaman zaman çerçeve özelliğini kullanmak için yararlı olabilir.

Kapsülleme alıcılar ve komut yöntemleri ile sağlanabilir. Ayarlayıcılar genellikle uygun değildir, çünkü değişmeyenlerin bakımı bir kerede değiştirilmek üzere birkaç alan gerektirebilirken, yalnızca tek bir alanı değiştirmeleri beklenir.

özet

alıcılar / yazıcılar oldukça zayıf kapsülleme sunar.

Java’da alıcıların / ayarlayıcıların yaygınlığı, özellikler için dil düzeyinde destek eksikliği ve pek çok öğretim materyalinde ve onlar tarafından öğretilen programcılarda yer alan tarihsel bileşen modelinde şüpheli tasarım seçimlerinden kaynaklanmaktadır.

EcmaScript gibi diğer nesne yönelimli diller dil seviyesindeki özellikleri desteklemektedir, böylece alıcılar API kırılmadan tanıtılabilir. Bu tür dillerde, alıcılar bir gün öncesinden ziyade, ihtiyaç duyduğunuzda, ihtiyaç duyduğunuzda, ihtiyaç duyduğunuzda, çok daha keyifli bir programlama deneyimi için ortaya çıkarılabilir.


1
değişmezlerini zorluyor mu? İngilizce mi Lütfen İngiliz olmayan bir kişiye açıklayabilir misiniz? Çok karmaşık olmayın - buradaki bazı insanlar yeterince iyi İngilizce bilmiyor.
Gangnus

Temeli beğenirim, düşüncelerini (+1) severim, fakat pratik sonucu değil. Yansıma yoluyla veri yüklemek için özel alanı ve bazı özel kütüphaneleri kullanmayı tercih ederim. Sadece cevabını neden bana karşı bir argüman olarak belirlediğini anlamıyorum.
Gangnus

@Gangnus Bir değişmez değişmeyen mantıksal bir durumdur (anlamsız ve anlamsız anlam değişir / değişir). Pek çok fonksiyonun, çalıştırmadan önce ve sonra (ön koşullar ve post-koşullar) denilen gerçek kuralları vardır, aksi halde kodda bir hata vardır. Örneğin, bir işlev, argümanının boş olmamasını gerektirebilir (bir ön koşul) ve argümanı null olduğunda bir istisna atabilir; çünkü bu durum kodda bir hata olur (örn. Bilgisayar bilimleri konuşmasında kod bir değişmez).
Pharap

@Gangus: Yansımanın bu tartışmaya nereden girdiğinden emin değil; Lombok bir açıklama işlemcisidir, yani derleme sırasında ek kod yayan Java derleyicisine bir eklentidir. Ama tabi ki, lombok kullanabilirsiniz. Sadece birçok durumda, kamuya açık alanların da iyi çalıştığını ve kurulmasının daha kolay olduğunu söylüyorum (tüm derleyiciler açıklama işlemcilerini otomatik olarak algılamamaktadır ...).
meriton

1
@ Gangnus: Değişkenler matematik ve CS'de aynıdır, ancak CS'de ek bir bakış açısı vardır: Bir nesnenin perspektifinden, değişmezlerin uygulanması ve oluşturulması gerekir. Bu nesnenin arayanı açısından, değişmezler her zaman doğrudur.
meriton

7

Kendime gerçekten bu soruyu sordum.

Yine de tamamen doğru değil. Alıcıların / belirleyicilerin IMO prevalansı, onu gerektiren Java Fasulyesi spesifikasyonundan kaynaklanmaktadır; bu yüzden hemen hemen Nesne Yönelimli programlama değil, Fasulye Yönelimli Programlama özelliğinin bir özelliğidir. İkisi arasındaki fark, içinde bulundukları soyutlama katmanınınkidir; Fasulye daha çok bir sistem arayüzüne, yani daha yüksek bir katmana sahiptir. Onlar OO toprak çalışmasından soyutlanırlar veya en azından - her zaman olduğu gibi işler yeterince sık tahrik edilir.

Java programlamada her yerde bulunan bu Bean şeyine karşılık gelen bir Java dili özelliğinin eklenmesi eşlik etmediğini biraz talihsiz olarak söyleyebilirim - C # 'daki Özellikler kavramı gibi bir şey düşünüyorum. Farkında olmayanlar için, şuna benzeyen bir dil yapısıdır:

class MyClass {
    string MyProperty { get; set; }
}

Her neyse, fiili uygulamanın nitrit taneciği, kapsüllemeden hala çok fazla yarar sağlıyor.


Python, özelliklerin saydam alıcı / ayarlayıcılara sahip olabileceği benzer bir özelliğe sahiptir. Eminim daha çok dilde de benzer özellikler vardır.
JAB

1
“IMO alıcıları / belirleyicileri prevalansı, onu gerektiren Java Fasulyesi spesifikasyonundan kaynaklanmaktadır” Evet, haklısınız. Ve kim gerekli olması gerektiğini söyledi? Sebep lütfen?
Gangnus

2
C # yolu kesinlikle bu Lombok ile aynı. Gerçek bir fark görmüyorum. Daha pratik kolaylık, ancak açıkça anlayışı kötü.
Gangnus

1
@Gangnis Şartname gerektirir. Neden? Alıcıların neden açık alanlarla aynı olmadığına dair somut bir örnek için cevabımı inceleyin - aynı şeyi alıcı olmadan yapmayı deneyin.
Vince Emigh

@VinceEmigh gangnUs, lütfen :-). çete yürüyüşü (nus - nut). Ve sadece özel olarak ihtiyaç duyduğumuz yerde get / set'i kullanmaya ve diğer durumlarda yansıma ile özel alanlara toplu yükleme yapmaya ne dersiniz?
Gangnus

6

Biri bana açıklayabilir mi, tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın anlamı nedir? Neden sadece ortak alanları kullanmıyoruz? Sadece başlangıç ​​noktasına geri dönmek için uzun ve zor bir yol yürüdüğümüzü hissediyorum.

Buradaki basit cevap şudur: kesinlikle haklısın. Alıcılar ve ayarlayıcılar, kapsülleme değerinin çoğunu (tümünü değil) ortadan kaldırır. Bu, kapsüllemeyi kırdığınız bir alma ve / veya set yöntemine sahip olduğunuz herhangi bir zamanınızın olduğunu söylememek değildir, ancak sınıfınızdaki tüm özel üyelere kör bir şekilde erişim sağlayıcı ekliyorsanız, yanlış yaptığınızı söylemek değildir.

Evet, alıcılar ve belirleyiciler aracılığıyla çalışan başka teknolojiler var. Ve bunları basit ortak alanlarda kullanamayız. Ancak bu teknolojiler sadece kamuoyunun alıcılarının / belirleyicilerinin ardındaki özel alanların olduğu özel mülklere sahip olduğumuz için ortaya çıktı. Bu özelliklere sahip olmasaydık, bu teknolojiler başka bir yol geliştirirdi ve ortak alanları desteklerdi. Ve her şey basit olacak ve şimdi Lombok'a ihtiyacımız olmayacaktı. Bütün bu döngünün anlamı nedir? Ve şimdi kapsülleme, gerçek hayattaki programlamada gerçekten bir anlam ifade ediyor mu?

Alıcılar ayarlayıcılardır, Java programlamada her yerde bulunur; çünkü JavaBean kavramı, işlevselliği önceden oluşturulmuş koda dinamik olarak bağlamak için bir yol olarak itti. Örneğin, bir uygulamada nesnenizi denetleyen, tüm özellikleri bulabilen ve alanları görüntüleyen bir formda (herkes bunları hatırlıyor mu?). Ardından, kullanıcı arayüzü kullanıcı girişine göre bu özellikleri değiştirebilir. Geliştirici olarak, o zaman sadece sınıfı yazmak için endişeleniyor ve orada herhangi bir doğrulama veya işletme mantığı koyuyorsunuz.

görüntü tanımını buraya girin

Örnek Fasulye Kullanma

Bu başlı başına korkunç bir fikir değil ama Java'daki yaklaşımın hiç bu kadar büyük bir hayranı olmadım. Sadece tahılı karşı gidiyor. Python, Groovy vb. Kullanın. Bu tür bir yaklaşımı daha doğal olarak destekleyen bir şey.

JavaBean meselesi kontrolden çıktı çünkü JOBOL'u yarattı, yani Java OO'yu anlamayan geliştiriciler. Temel olarak, nesneler veri paketlerinden başka bir şey haline gelmedi ve tüm mantık dışardan uzun yöntemlerle yazıldı. Normal olarak görüldüğünden, bunu sorgulayan siz ve benim gibi insanlar kola olarak kabul edildi. Son zamanlarda bir kayma gördüm ve bu yabancı bir konum kadar değil

XML bağlayıcı şey zor bir somun. Bu muhtemelen JavaBeans'a karşı durmak için iyi bir savaş alanı değil. Bu JavaBeans'ı oluşturmanız gerekiyorsa, onları gerçek kodların dışında tutmaya çalışın. Onlara serileştirme katmanının bir parçası olarak davranın.


2
En somut ve akıllıca düşünceler. +1. Fakat neden her biri özel alanlardan bazılarını harici bir yapıya toplu olarak yükleyecek / kaydedecek bir sınıflar grubu yazmıyorsunuz? JSON, XML, diğer nesne. POJO'larla veya belki de yalnızca bunun için bir açıklama ile işaretlenmiş alanlarla çalışabilir. Şimdi bu alternatifi düşünüyorum.
Gangnus

@ Gangnus Bir tahmin, çünkü bu çok fazladan kod yazmanın anlamı. Eğer yansıma kullanılırsa, o zaman sadece bir seri hale getirme kodu yazılmalıdır ve belirli bir modeli takip eden herhangi bir sınıfı seri hale getirebilir. C #, [Serializable]niteliği ve yakınları aracılığıyla bunu destekler . Yansımayı kaldırarak yazarken neden 101 özel seri hale getirme yöntemi / sınıfı yazmalısınız?
Pharap

@Pharap Çok üzgünüm ama yorumunuz benim için çok kısa. "yansıma kaldıraç"? Ve bu kadar farklı şeyleri bir sınıfa saklamanın anlamı nedir? Ne demek istediğini açıklayabilir misin?
Gangnus

@ Gangnus yansıması , kodun kendi yapısını inceleme yeteneği. Java'da (ve diğer dillerde), bir sınıfın ortaya koyduğu tüm işlevlerin bir listesini alabilir ve bunları, bunları XML / JSON'a serileştirmek için gereken sınıftan veri ayıklamak için kullanabilirsiniz. Yapıları sınıf bazında kurtarmak için sürekli yeni yöntemler kullanmak yerine, bir kereye mahsus bir iş olacak olan yansıması kullanmak. İşte basit bir Java örneği .
Pharap

@Pharap Sadece bahsettiğim şey buydu. Ama neden buna "kaldıraç" diyorsun? Ve ilk yorumda bahsettiğim alternatif burada kalır - (un) doldurulmuş alanların özel ek açıklamaları olmalı mı yoksa içermelidir?
Gangnus

5

Alıcılar olmadan ne kadar yapabiliriz? Onları tamamen kaldırmak mümkün mü? Bu hangi problemleri yaratır? returnAnahtar kelimeyi bile yasaklayabilir miyiz ?

İşi yapmaya istekliysen çok şey yapabilirsin. Öyleyse bilgi bu tamamen kapsüllenmiş nesneden nasıl çıkar? Bir ortak çalışan aracılığıyla.

Kod size soru sormak yerine, bir şeyler yapman gerektiğini söylersin. Eğer bunlar da bir şeyleri geri getirmezse, geri döndükleri hakkında hiçbir şey yapmanıza gerek kalmaz. Yani returnbunun yerine ulaşmayı düşünürken, yapılması gerekenleri yapacak olan çıkış portu ortak çalışanına ulaşmayı deneyin.

İşleri bu şekilde yapmanın faydaları ve sonuçları vardır. Geri döndüreceğin şeyden daha fazlasını düşünmelisin. Bunu, bunu istemeyen bir nesneye mesaj olarak nasıl göndereceğinizi düşünmelisiniz. Dönmüş olacağınız nesneyi dışarı atmış olabilirsiniz ya da bir yöntemi çağırmanız yeterli olabilir. Bu düşünce yapmanın bir bedeli var.

Bunun yararı şu anda konuşmanızı arayüzle yüzleşerek yapıyor olmanızdır. Bu, soyutlamanın tüm avantajlarından yararlanacağınız anlamına gelir.

Aynı zamanda size polimorfik gönderim sağlar, çünkü ne dediğinizi bildiğiniz halde tam olarak ne dediğinizi bilmek zorunda değilsiniz.

Bunun, bir katman yığınının sadece bir yolundan gitmeniz gerektiği anlamına geldiğini düşünebilirsiniz, ancak çılgınca döngüsel bağımlılıklar yaratmadan geriye gitmek için polimorfizmi kullanabileceğiniz ortaya çıkıyor.

Bu gibi görünebilir:

Resim tanımını buraya girin

class Interactor implements InputPort {
    OutputPort out;
    int y = 0;

    Interactor(OutputPort out){
        this.out = out;
    }

    void accumulate(int x) {
        y = y + x;
        out.showAsImage(y);
    }
}

Böyle bir kod yazabiliyorsanız, alıcıları kullanmak bir seçimdir. Gerekli bir kötülük değil.


Evet, bu alıcılar / ayarlayıcılar büyük bir anlam ifade ediyor. Fakat bunun başka bir şeyle ilgili olduğunu anlıyor musunuz? :-) yine de +1.
Gangnus

1
@ Gangnus Teşekkürler. Konuşabileceğin bir sürü şey var. En azından onlara isim vermek istersen, onlara girebilirim.
candied_orange 6:17

5

Bu tartışmalı bir konudur (gördüğünüz gibi) çünkü bir grup dogma ve yanlış anlama, alıcılar ve belirleyicilerle ilgili makul kaygılarla karıştırılmıştır. Ancak kısacası, yanlış olan hiçbir şey yoktur @Datave kapsüllemeyi bozmaz.

Neden halka açık alanlar yerine alıcı ve ayarlayıcıları kullanıyorsunuz?

Çünkü alıcılar / alıcılar kapsülleme sağlar. Bir değeri genel alan olarak gösterip daha sonra anında değeri hesaplamaya geçerseniz, alana erişen tüm müşterileri değiştirmeniz gerekir. Açıkçası bu kötü. Bir nesnenin bazı özelliklerinin bir alanda depolanıp depolanmadığı, anında üretilip getirilmediği veya başka bir yerden getirilip getirilmediği bir uygulama detayıdır, bu nedenle fark müşterilere gösterilmemelidir. Getter / setters setter bunu çözüyor çünkü uygulamayı gizliyorlar.

Ancak alıcı / ayarlayıcı sadece altta yatan bir özel alanı yansıtıyorsa, o kadar kötü değil mi?

Hayır! Önemli olan, kapsülleme , müşterileri etkilemeden uygulamayı değiştirmenize olanak sağlamasıdır. Bir alan hala, müşterilerin bilmek veya ilgilenmek zorunda kalmaması koşuluyla, değeri depolamak için mükemmel bir yol olabilir.

Fakat otomatik üreteç veren alıcılar / alıcılar kapsüllemeyi bozan alanlardan değil mi?

Hayır, kapsülleme hala orada! @Dataek açıklamalar, altta yatan bir alanı kullanan alıcı / ayarlayıcı çiftlerini yazmak için uygun bir yoldur. Bir müşterinin bakış açısı için bu normal bir alıcı / ayarlayıcı çifti gibidir. Uygulamayı yeniden yazmaya karar verirseniz, müşteriyi etkilemeden yine de yapabilirsiniz. Böylece her iki dünyanın en iyisini elde edersiniz: kapsülleme ve özlü sözdizimi.

Ancak bazıları, alıcıların / ayarlayıcıların her zaman kötü olduğunu söylüyor!

Bazılarının alıcı / belirleyici modelinin, temeldeki uygulamadan bağımsız olarak her zaman kötü olduğuna inandığı ayrı bir tartışma vardır . Buradaki fikir, nesnelerden değer ayarlamamanız veya almamanız gerektiğidir, bunun yerine nesneler arasındaki etkileşimler, bir nesnenin başka bir nesnenin bir şey yapmasını istediği mesajlar olarak modellenmelidir . Bu, çoğunlukla nesneye yönelik düşüncenin ilk günlerinden kalma bir dogma parçasıdır. Şimdiki düşünce, belirli modeller için (örneğin, değer nesneleri, veri aktarım nesnesi) alıcıların / ayarlayıcıların mükemmel şekilde uygun olabileceğidir.


Kapsülleme bize polimorfizm ve güvenlik sağlamalıdır. Alır / kümeler köknarlara izin verir, ancak ikinciye karşı şiddetle karşı çıkarlar.
Gangnus

Bir yerde bir dogma kullandığımı söylerseniz, lütfen yazının ne olduğunu dogma deyin. Ve unutma, kullandığım bazı düşüncelerin hoşuma gitmediğini veya aynı fikirde olmadığını. Onları bir çelişki göstermesi için kullanıyorum.
Gangnus

1
"GangNus" :-). Bir hafta önce, kelimenin tam anlamıyla birkaç katmana çağrı yapan alıcı ve ayarlayıcılarla dolu bir projede çalıştım. Kesinlikle güvensiz ve daha da kötüsü, güvensiz kodlamada insanları destekliyor. İnsanların bu şekilde alışması için işleri yeterince hızlı değiştirdiğim için memnunum . Yani sanmıyorum, görüyorum .
Gangnus

2
@jrh: Bunun gibi resmi bir açıklama olup olmadığını bilmiyorum, fakat C # özellikleri (daha iyi sözdizimi olan alıcılar / ayarlayıcılar) ve yalnızca özellikli ve davranışsız türler olan adsız türler için yerleşik desteğe sahip . Bu yüzden C # tasarımcıları kasıtlı olarak mesajlaşma metaforundan ayrıldı ve “söyle, sorma” prensibine. 2.0 sürümünden beri C # 'nın gelişimi, geleneksel OO saflığına göre işlevsel dillerden daha fazla ilham almış gibi görünüyor.
JacquesB

1
@jrh: Şimdi tahmin ediyorum, ama C # 'nın veri ve işlemlerin daha ayrı olduğu fonksiyonel dillerden oldukça ilham aldığını düşünüyorum. Dağınık mimarilerde, perspektif de mesaj yönelimli (RPC, SOAP) veri yönelimli (REST) ​​'e doğru kaymıştır. Ve verileri açığa çıkaran ve üzerinde çalışan ("kara kutu" nesneler değil) veritabanları esas alınmıştır. Kısacası, odaklanmanın kara kutular arasındaki mesajlardan açığa
çıkmış

3

Enkapsülasyonun bir amacı vardır, fakat aynı zamanda kötüye de kullanılabilir.

Düzinelerce (yüzlerce olmasa) alan içeren sınıflara sahip Android API gibi bir şey düşünün. Bu alanların kullanılması, API tüketicisinin gezinmesini ve kullanılmasını zorlaştırır; ayrıca, kullanıcının nasıl kullanılması gerektiği ile çelişebilecek alanlarla ne isterse yapabileceği konusunda yanlış bir fikir verir. Bu yüzden, kapsülleme, bu anlamda sürdürülebilirlik, kullanılabilirlik, okunabilirlik ve çılgın böceklerden kaçınmak için mükemmeldir.

Öte yandan, tüm alanların ortak olduğu C / C ++ 'dan bir yapı gibi POD veya düz eski veri türleri de yararlı olabilir. Lombok'taki @tata notları tarafından üretilenler gibi işe yaramaz alıcı / ayarlayıcılara sahip olmak, "Kapsülleme modelini" korumanın bir yoludur. Java’daki alıcı / ayarlayıcıları “işe yaramaz” olarak almamızın birkaç nedeni, yöntemlerin bir sözleşme sunmasıdır .

Java'da, bir arayüzde alanlar olamaz, bu nedenle bu arayüzün tüm uygulayıcılarının sahip olduğu ortak bir özellik belirtmek için alıcıları ve ayarlayıcıları kullanırsınız. Kotlin veya C # gibi daha yeni dillerde, mülk kavramını belirleyiciyi ve alıcıyı ilan edebileceğiniz alanlar olarak görüyoruz. Sonunda, işe yaramaz alıcılar / alıcılar, Oracle'a özellikler eklemediği sürece Java'nın yaşamak zorunda olduğu daha fazla eskidir. Örneğin, JetBrains tarafından geliştirilen başka bir JVM dili olan Kotlin, temel olarak @tata anonsunun Lombok'ta yaptığı şeyi yapan veri sınıflarına sahiptir.

Ayrıca burada birkaç örnek:

class DataClass 
{
    private int data;

    public int getData() { return data; }
    public void setData(int data) { this.data = data; } 
}

Bu kötü bir kapsülleme durumudur. Alıcı ve alıcı, etkili bir şekilde işe yaramaz. Kapsülleme çoğunlukla kullanılır, çünkü bu Java gibi dillerde standarttır. Kod bazında tutarlılığı korumanın yanı sıra aslında yardımcı olmuyor.

class DataClass implements IDataInterface
{
    private int data;

    @Override public int getData() { return data; }
    @Override public void setData(int data) { this.data = data; }
}

Bu iyi bir kapsülleme örneğidir. Kapsülleme bir sözleşmeyi uygulamak için kullanılır, bu durumda IDataInterface. Bu örnekte kapsüllemenin amacı, bu sınıftaki tüketicinin arayüz tarafından sağlanan yöntemleri kullanmasını sağlamaktır. Alıcı ve ayarlayıcı hiçbir şey fantezi yapmasa da, DataClass ve diğer IDataInterface uygulayıcıları arasında ortak bir özellik tanımladık. Böylece böyle bir yöntem olabilir:

void doSomethingWithData(IDataInterface data) { data.setData(...); }

Şimdi, kapsülleme hakkında konuşurken sözdizimi sorununa da değinmenin önemli olduğunu düşünüyorum. Çoğu zaman insanların kapsüllemenin kendisinden ziyade kapsüllemeyi zorlamak için gerekli olan sözdiziminden şikayet ettiğini görüyorum. Akla gelen bir örnek Casey Muratori'dendir ( burada rantını görebilirsiniz ).

Kapsülleme kullanan ve pozisyonunu 1 birim hareket ettirmek isteyen bir oyuncu sınıfınız olduğunu varsayalım. Kod şöyle görünür:

player.setPosX(player.getPosX() + 1);

Kapsülleme olmadan şöyle görünürdü:

player.posX++;

Burada, enkapsülasyonların ek faydaları olmadan daha fazla yazmaya yol açtığını ve bunun birçok durumda doğru olabileceğini, ancak bir şeyin farkına varabileceğini savunuyor. Argüman, kapsülleme değil, sözdizimine karşıdır. Kapsülleme kavramına sahip olmayan C dillerinde bile, genellikle '_' veya 'my' ile önceden belirlenmiş veya eklenmiş yapılardaki değişkenleri görürsünüz ya da API tüketicileri tarafından, sanki API tüketicileri tarafından kullanılmaması gerektiğini belirtmek için ne olursa olsun. özel.

Maddenin gerçeği, kapsülleme, kodun daha sürdürülebilir ve kullanımı kolay olmasına yardımcı olabilir. Bu sınıfı düşünün:

class VerticalList implements ...
{
    private int posX;
    private int posY;
    ... //other members

    public void setPosition(int posX, int posY)
    {
        //change position and move all the objects in the list as well
    }
}

Değişkenler bu örnekte halka açıksa, bu API'nin bir tüketicisi posX ve posY ne zaman ve ne zaman setPosition () kullanılacağıyla ilgili olarak karıştırılır. Bu ayrıntıları gizleyerek tüketicinin API'nizi sezgisel bir şekilde daha iyi kullanmasına yardımcı olursunuz.

Sözdizimi olsa da birçok dilde bir sınırlamadır. Bununla birlikte, yeni diller bize publice üyelerinin güzel sözdizimini ve enkapsülasyonun yararlarını sağlayan özellikler sunar. MSVC kullanıyorsanız, özellikleri C #, Kotlin'de, hatta C ++ 'da bulacaksınız. Kotlin'de bir örnek.

sınıf VerticalList: ... {var posX: Int set (x) {alan = x; ...} var posY: Int (y) ayarlayın {field = y; ...}}

Burada Java örneğindekiyle aynı şeyi başardık, ancak posX ve posY komutlarını ortak değişkenlermiş gibi kullanabiliriz. Değerlerini değiştirmeye çalıştığımda, set () setçığının gövdesi çalıştırılacak.

Örneğin Kotlin'de bu, alıcıların, ayarlayıcıların, hashcode'un, eşit değerlerin ve toString'in uygulandığı Java Bean'in eşdeğeri olacaktır:

data class DataClass(var data: Int)

Bu sözdiziminin Java Bean'i bir satırda yapmamıza izin verdiğine dikkat edin. Java gibi bir dilin kapsülleme uygulamasındaki sorunu doğru bir şekilde fark ettiniz, ancak bu Java'nın kapsüllemenin kendisinin hatası değil.

Alıcıları ve ayarlayıcıları oluşturmak için Lombok'un @ Verisini kullandığını söyledin. Adı, @ Verisi dikkat edin. Çoğunlukla yalnızca veri depolayan ve seri hale getirilmiş ve seri hale getirilmiş veri sınıflarında kullanılmak içindir. Bir oyundan tasarruf dosyası gibi bir şey düşünün. Ancak diğer senaryolarda, bir UI öğesinde olduğu gibi, en kesin şekilde ayarlayıcıları istersiniz, çünkü yalnızca bir değişkenin değerini değiştirmek beklenen davranışı elde etmek için yeterli olmayabilir.


Buraya enkapsülasyonun yanlış kullanımı hakkında bir örnek verebilir misiniz? Bu ilginç olabilir. Örneğin, kapsülleme eksikliğine karşı.
Gangnus

1
@ Gangnus Birkaç örnek ekledim. İşe yaramaz enkapsülasyon genellikle yanlış ve aynı zamanda benim deneyimimden dolayı API geliştiricileri sizi bir API'yi belirli bir şekilde kullanmaya zorlamak için çok çaba harcıyorlar. Buna bir örnek vermedim çünkü sunacak kolay bir örneğim yoktu. Bir tane bulursam, kesinlikle ekleyeceğim. Bence enkapsülasyona karşı çoğu yorum, enkapsülasyonun kendisinden ziyade, enkapsülasyon sözdizimine karşıdır.
BananyaDev

Düzenleme için teşekkürler. Küçük bir yazım hatası buldum: "public" yerine "publice".
jrh

2

Kapsülleme size esneklik verir . Yapıyı ve arayüzü ayırarak, arayüzü değiştirmeden yapıyı değiştirmenize izin verir.

Örneğin, inşaatta temel alanı başlatmak yerine, diğer alanlara göre bir özellik hesaplamanız gerektiğine karar verirseniz, alıcıyı değiştirebilirsiniz. Alanı doğrudan maruz bırakmış olsaydınız, arayüzü kullanmak ve her kullanım yerinde değişiklik yapmanız gerekirdi.


Teoride iyi bir fikir olsa da, bir API'nin 2. sürümünün 1. sürümün kütüphanenizdeki veya sınıfınızdaki kullanıcıları korkunç bir şekilde bozmayacağına dair istisnalar atmasına (ve muhtemelen sessizce!); Bu veri sınıflarının çoğunda herhangi bir büyük değişikliğin "perde arkasından" yapılabileceğinden şüpheliyim.
jrh

Üzgünüz, bu bir açıklama değil. Arabirimlerde tarla kullanımının yasaklanması, kapsülleme fikrinden kaynaklanmaktadır. Ve şimdi bunun hakkında konuşuyoruz. Tartışılan gerçeklere dayanıyorsunuz. (dikkat, yanlısı değilim ya da düşüncelerinizle
çelişmiyorum

@Gangnus "Arayüz" kelimesi sadece Java anahtar kelimesi dışında bir anlam ifade ediyor: dictionary.com/browse/interface
glennsl 5:17

@jrh Bu tamamen farklı bir konu. Belirli bağlamlarda kapsüllemeye karşı savunmak için kullanabilirsiniz , ancak bu herhangi bir şekilde onun argümanlarını geçersiz kılmaz.
glennsl

1
Eski kapsülleme, kitle toparlanmadan / ayarlanmadan bize sadece Polimorfizm'i değil aynı zamanda güvenliği de verdi. Ve kitle setleri bize kötü uygulamalara karşı öğretir.
Gangnus

2

Kapsülleme ve sınıf tasarımının problem alanını göstermeye çalışacağım ve sorunuzu sonunda cevaplayacağım.

Diğer cevaplarda belirtildiği gibi, kapsülleme amacı, bir nesnenin iç detaylarını, bir sözleşme olarak hizmet eden bir kamu API'sinin arkasına gizlemektir. Nesne, içini değiştirmek için güvenlidir, çünkü yalnızca genel API üzerinden çağrıldığını bilir.

Genel alanlara, alıcılara / alıcılara veya daha üst düzey işlem yöntemlerine veya mesaj iletmeye sahip olmanın mantıklı olup olmadığı, modellenmekte olan etki alanının doğasına bağlıdır. Akka Eşzamanlılık kitabında (biraz güncel olmasa bile önerebileceğim) kitabında, burada kısaltma yapacağım bir örnek bulacaksınız.

Bir kullanıcı sınıfı düşünün:

public class User {
  private String first = "";
  private String last = "";

  public String getFirstName() {
    return this.first;
  }
  public void setFirstName(String s) {
    this.first = s;
  }

  public String getLastName() {
    return this.last;
  }
  public void setLastName(String s) {
    this.last = s;
  }
}

Bu tek iş parçacıklı bir bağlamda iyi çalışıyor. Modellenen alan bir kişinin adıdır ve bu adın nasıl kaydedildiğinin mekaniği ayarlayıcılar tarafından mükemmel bir şekilde kapsanabilir.

Ancak, bunun çok iş parçacıklı bir bağlamda sağlanması gerektiğini düşünün. Bir iş parçacığının adı düzenli olarak okuduğunu varsayalım:

System.out.println(user.getFirstName() + " " + user.getLastName());

Diğer iki başlık ise sırayla Hillary Clinton ve Donald Trump’a ayarlanan bir halat çekme mücadelesi veriyor . Her birinin iki yöntem çağırması gerekir. Çoğunlukla bu işe yarar, fakat arada bir Hillary Trump veya Donald Clinton'un geçtiğini göreceksiniz .

Bu sorunu, ayarlayıcıların içine bir kilit ekleyerek çözemezsiniz, çünkü kilit yalnızca ilk adı veya soyadı belirleme süresi boyunca tutulur. Kilitleme yoluyla tek çözüm, tüm nesnenin etrafına bir kilit eklemektir, ancak çağıran kod kilidi yönetmesi gerektiğinden (ve kilitlenmelere neden olabilir) kapsüllemeyi kırar.

Görünüşe göre, kilitleme yoluyla temiz bir çözüm yoktur. Temiz çözüm, iç kısımları daha kaba hale getirerek tekrar kapsüllemek:

public class UserName {
   public final String first;
   public final String last;
   public UserName(String first, String last) { ... }
}

public class User
   private UserName name;
   public UserName getName() { return this.name; }
   public setName(UserName n) { this.name = n; }
}

Bu adın kendisi değişmez hale geldi ve üyelerin herkese açık olabileceğini görüyorsunuz, çünkü artık bir kez oluşturulduğunu değiştirme yeteneği olmayan saf bir veri nesnesi. Buna karşılık, Kullanıcı sınıfının genel API'si, yalnızca tek bir ayarlayıcı kaldığında daha da kaba bir hale geldi, böylece ad yalnızca bir bütün olarak değiştirilebilir. API'nin arkasında iç durumunun çoğunu kapsar.

Bütün bu döngünün anlamı nedir? Ve şimdi kapsülleme, gerçek hayattaki programlamada gerçekten bir anlam ifade ediyor mu?

Bu döngüde gördüğünüz şey, çok geniş bir şekilde belirli koşullar için iyi olan çözümleri uygulama girişimleridir. Uygun bir kapsülleme seviyesi, modellenmekte olan alanın anlaşılmasını ve doğru kapsülleme seviyesinin uygulanmasını gerektirir. Bazen bu, tüm alanların ortak olduğu anlamına gelir, bazen (Akka uygulamalarında olduğu gibi), mesaj almak için tek bir yöntem dışında hiçbir genel API'niz olmadığı anlamına gelir. Bununla birlikte, kapsülleme kavramının kendisi, dahili bir sistemin istikrarlı bir API'nin arkasına gizlenmesini ifade eder, özellikle çok iş parçacıklı sistemlerde programlama yazılımı için anahtardır.


Fantastik. Tartışmayı bir üst seviyeye çıkardığını söyleyebilirim. Belki iki tane. Gerçekten, kapsüllemeyi anladığımı ve bazen standart kitaplardan daha iyi anladığımı düşündüm ve kabul edilen bazı gelenekler ve teknolojilerden dolayı pratikte kaybediyor olmamızdan gerçekten korktum. iyi yol), ama bana kapsüllemenin gerçekten yeni taraflarını gösterdin. Çoklu görevde kesinlikle iyi değilim ve bana diğer temel prensipleri anlamanın ne kadar zararlı olabileceğini gösterdiniz.
Gangnus

Ama olarak yazı işaretleyemezsiniz o nesnelerden için / kütle veri yükleme, fasulye ve Lombok gibi platformlar görünür hangi nedeniyle sorun hakkında değil için, cevap. Belki, düşüncelerinizi bu yönde detaylandırabilir misiniz? Ben kendim henüz düşüncenizin bu soruna getirdiği sonuçları yeniden düşünmedim. Ve bunun için yeterince uygun olduğumdan emin değilim (unutmayın, kötü
okuyucunun

Lombok'u kullanmadım, ama anladığım kadarıyla, daha az yazarak belirli bir kapsülleme (her alanda alıcı / ayarlayıcı) uygulamanın bir yoludur. Sorunlu etki alanınız için API'nin ideal şeklini değiştirmez, daha hızlı bir şekilde yazmanız için bir araçtır.
Joeri Sebrechts

1

Bunun mantıklı olduğu bir kullanım durumu düşünebilirim. Başlangıçta basit bir alıcı / ayarlayıcı API'sından erişeceğiniz bir sınıfa sahip olabilirsiniz. Daha sonra, artık aynı alanları kullanmayacak, ancak yine de aynı API'yı desteklemesi için genişletir veya değiştirirsiniz .

Biraz da olsa örnek: p.x()ve ile Kartezyen çifti olarak başlayan bir nokta p.y(). Daha sonra kutupsal koordinatlar kullanan yeni bir uygulama veya alt sınıf oluşturursunuz; böylece p.r()ve ayrıca p.theta()ancak arama yapan p.x()ve p.y()geçerli olan müşteri kodunuzu da arayabilirsiniz . Sınıfın kendisi şeffaf bir şekilde iç kutup biçiminden, yani y()şimdi olur return r * sin(theta);. (Bu örnekte, yalnızca ayar x()veya y()çok anlamlı olmamakla birlikte, yine de mümkündür.)

Bu durumda, “Alanları kamusal hale getirmek yerine alıcıları ve belirleyicileri otomatik olarak ilan etmekten rahatsız oldum veya API'mı orada kırmak zorunda kaldım” diyerek kendinizi bulabilirsiniz.


2
Gördüğün kadar hoş değil. İç fiziksel temsili değiştirmek gerçekten nesneyi farklı kılar. Ve aynı şekilde görünmeleri kötü , çünkü farklı niteliklere sahipler. Descartes sistemi özel noktalara sahip değildir, kutup sistemi bir noktaya sahiptir.
Gangnus

1
Bu belirli örneği sevmiyorsanız, kesinlikle gerçekten çok sayıda eşdeğer gösterimi olan başkalarını veya daha eski birine dönüştürülebilen daha yeni bir gösterimi düşünebilirsiniz.
Davislor

Evet, sunum için onları çok verimli bir şekilde kullanabilirsiniz. Kullanıcı Arabiriminde yaygın olarak kullanılabilir. Ama kendi soruma cevap vermemi sağlamıyor musun? :-)
Gangnus

Bu şekilde daha verimli, değil mi? :)
Davislor

0

Biri bana açıklayabilir mi, tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın anlamı nedir?

Kesinlikle bir anlamı yok. Bununla birlikte, bu soruyu sorduğunuz gerçeği, Lombok'un ne yaptığını anlamadığınızı ve OO kodunu kapsülleme ile nasıl yazacağınızı anlamadığınızı gösterir. Biraz geri saralım ...

Sınıf örneği için bazı veriler her zaman içsel olacaktır ve hiçbir zaman açığa çıkmamalıdır. Bir sınıf örneği için bazı verilerin harici olarak ayarlanması gerekebilir ve bazı verilerin bir sınıf örneğinden geri aktarılması gerekebilir. Sınıfın yüzeyin altındaki işleri nasıl yapacağını değiştirmek isteyebiliriz, bu yüzden veri almamıza ve ayarlamamıza izin veren fonksiyonları kullanırız.

Bazı programlar sınıf örnekleri için durum kaydetmek ister, bu nedenle bazı serileştirme arayüzleri olabilir. Sınıf örneğinin durumunu depolamaya ve durumunu depodan almasına izin veren daha fazla işlev ekleriz. Bu, kapsüllemeyi korur çünkü sınıf örneği hala kendi verilerinin kontrolündedir. Özel verileri seri hale getirebiliriz, ancak programın geri kalanının buna erişimi yok (veya daha doğrusu, o özel verileri kasten bozmamayı seçerek bir Çin Duvarı koruyoruz ) ve sınıf örneği de yapabilir (ve gerekir) verilerinin geri döndüğünden emin olmak için seri kaldırma üzerinde bütünlük kontrolleri yapın.

Bazen veri, aralık kontrolleri, bütünlük kontrolleri veya benzeri şeyler gerektirir. Bu fonksiyonları kendimiz yazmak, hepsini yapmamıza izin veriyor. Bu durumda Lombok'u istemiyoruz ya da istemiyoruz, çünkü hepsini kendimiz yapıyoruz.

Sık sık, harici olarak ayarlanmış bir parametrenin tek bir değişkende saklandığını görüyorsunuz. Bu durumda, bu değişkenin içeriğini almak / ayarlamak / serileştirmek / seri hale getirmek için dört işleve ihtiyacınız olacaktır. Bu dört işlevi her zaman kendiniz yazmak sizi yavaşlatır ve hatalara açıktır. Lombok ile işlemi otomatikleştirmek gelişiminizi hızlandırır ve hata olasılığını ortadan kaldırır.

Evet, bu değişkeni herkese açık yapmak mümkün olurdu. Kodun bu özel versiyonunda, işlevsel olarak aynı olacaktır. Fakat neden fonksiyonları kullanıyoruz diye dönün: “Sınıfın yüzeyin altında iş yapma şeklini değiştirmek isteyebiliriz…” Değişkeninizi genel yaparsanız, kodunuzu şimdi ve sonsuza kadar bu genel değişkene sahip olmak için kısıtlıyorsunuzdur. arayüz. Yine de işlevleri kullanıyorsanız veya Lombok'u bu işlevleri sizin için otomatik olarak oluşturmak için kullanıyorsanız, temel verileri ve temeldeki uygulamayı gelecekte istediğiniz zaman değiştirmekte özgürsünüz.

Bu netleştiriyor mu?


Birinci sınıf öğrencisinin soruları hakkında konuşuyorsunuz. Biz zaten başka bir yerdeyiz. Bunu asla söyleyemem ve hatta cevabınız kadar kaba olmasanız bile, akıllıca cevaplar için bir artı bile verirdim.
Gangnus

0

Aslında bir Java geliştiricisi değilim; ancak aşağıdaki hemen hemen platform agnostik.

Yazdığımız her şey, özel değişkenlere erişen genel alıcılar ve ayarlayıcılar kullanır. Alıcıların ve belirleyicilerin çoğu önemsiz. Ancak ayarlayıcının bir şeyi yeniden hesaplaması gerektiğine karar verdiğimizde veya ayarlayıcı bazı doğrulama yaparsa veya özelliği bu sınıfın üye değişkeninin bir özelliğine iletmemiz gerektiğinden, bu tüm kodu tamamen bozmaz ve ikili uyumludur. Bir modülü yerinden çıkarabilir.

Bu özelliğin gerçekten hesaplanması gerektiğine karar verdiğimizde, ona bakacak tüm kodun değişmesi gerekmez ve yalnızca kendisine yazan kodun değişmesi gerekir ve IDE bunu bizim için bulabilir. Bunun yazılabilir bir bilgisayarlı alan olduğuna karar verdiğimizde (bunu yalnızca birkaç kez yapmak zorunda kaldı), bunu da yapabiliriz. Güzel olan şey, bu değişikliklerden birkaçı ikili uyumludur (salt okunur hesaplanan alana geçmek teoride değildir ancak yine de pratikte olabilir).

Karmaşık belirleyicilere sahip olan birçok ve çok sayıda önemsiz alıcı ile son bulduk. Biz de birkaç önbellek alıcı ile sona erdi. Sonuçta, alıcıların oldukça ucuz olduğunu varsaymanıza izin verilir, ancak ayarlayıcılar olmayabilir. Öte yandan, ayarlayıcıların diske kalmamasına karar verecek kadar akıllıyız.

Ancak, tüm üye değişkenlerini kör bir şekilde özelliklere değiştiren adamı bulmak zorunda kaldım. Hangi atomik eklemenin ne olduğunu bilmiyordu, bu yüzden bir mülk için genel bir değişken olması gereken şeyi değiştirdi ve kodu ince bir şekilde kırdı.


Java dünyasına hoş geldiniz. (C # de). *iç çekmek*. Ancak iç gösterimi gizlemek için get / set kullanmak için dikkatli olun. Sadece dış format ile ilgili, sorun değil. Fakat eğer matematikle ilgili veya daha da kötüsü, fizik veya başka bir gerçek şeyse, farklı içsel temsillerin farklı nitelikleri vardır. benim yorumum yani softwareengineering.stackexchange.com/a/358662/44104
Gangnus

@ Gangnus: Bu nokta örneği en talihsiz. Bunlardan birkaçı vardı ancak hesaplama her zaman kesindi.
Joshua,

-1

Alıcılar ve düzenleyiciler, geliştirme sürecinde iç yapı veya erişim gereklilikleri değiştiğinde gelecekte yeniden düzenlemekten kaçınmak için eklenen bir önlemdir.

Diyelim ki, piyasaya çıktıktan birkaç ay sonra müşteriniz, bu durumda en fazla 0 değerine bağlanması gerekmesine rağmen, sınıf alanlarından birinin bazen negatif değerlere ayarlandığını size bildirir. Genel alanları kullanarak, sıkıştırma işlevini belirleyeceğiniz değere uygulamak için kod alanınızdaki bu alanın her atamasını aramanız ve bu alanı değiştirirken her zaman bunu yapmanız gerektiğini aklınızda bulundurmanız gerekir. ama bu berbat. Bunun yerine, zaten alıcı ve ayarlayıcı kullanıyor olsaydınız, bu kelepçelemenin her zaman uygulanmasını sağlamak için sadece setField () yönteminizi değiştirebildiniz.

Şimdi, Java gibi "eski" dillerle ilgili sorun, bu amaçla yöntemlerin kullanılmasını teşvik etmeleridir. Yazmak acı verici ve okunması zor, bu yüzden bu sorunu bir şekilde veya başka şekilde hafifleten IDE kullanıyoruz. Çoğu IDE sizin için otomatik olarak alıcı ve ayarlayıcılar üretecek ve aksi belirtilmedikçe bunları gizleyecektir. Lombok bir adım daha ileri gidiyor ve kodunuzu ekstra şık tutmak için derleme sırasında bunları usule uygun şekilde oluşturuyor. Ancak, diğer daha modern diller bu konuyu bir şekilde veya başka bir yolla çözmüştür. Scala veya .NET dilleri, örneğin,

Örneğin, VB .NET veya C # 'de, basit, hiçbir yan etkisi olmayan ve ayarlayıcıları yalnızca genel alanlara sahip olacak tüm alanları yapabilir ve daha sonra bunları özel yapabilir, adlarını değiştirebilir ve bir önceki adıyla bir Özellik gösterebilir İhtiyacınız olursa, alanın erişim davranışında ince ayar yapabileceğiniz alan. Lombok ile, bir alıcı veya ayarlayıcının davranışında ince ayar yapmanız gerekirse, bu etiketleri gerektiğinde kolayca kaldırabilir ve başka dosyalardaki hiçbir şeyi yeniden düzenlemek zorunda kalmayacağınızı bilerek, yeni gereksinimlerle kendi kodunuzu yazabilirsiniz.

Temel olarak, yönteminizin bir alana erişme şekli saydam ve tekdüze olmalıdır. Modern diller, bir alanın aynı erişim / çağrı sözdizimine sahip "yöntemler" tanımlamanıza izin verir, böylece bu değişiklikler erken gelişme sırasında çok fazla düşünmeden talep üzerine yapılabilir, ancak Java sizi bu işi önceden yapması için zorlar çünkü bu özelliğe sahip değil. Tüm Lombok size biraz zaman kazandırıyor, çünkü kullandığınız dil "sadece durumda" yöntemi için zaman kazanmanıza izin vermek istemiyordu.


Bu "modern" diller, API benziyor saha erişimi foo.barama olabilir bir yöntem çağrısı tarafından ele almak. Bunun, bir API'nın yöntem çağrıları gibi görünmesinin "eski" yönteminden üstün olduğunu iddia ediyorsunuz foo.getBar(). Kamusal alanların sorunlu olduğu konusunda hemfikiriz gibi gözüküyor, ancak "eski" alternatifin "modern" olandan daha üstün olduğunu iddia ediyorum, çünkü tüm API'larımız simetriktir (hepsi yöntem çağrılarıdır). “Modern” yaklaşımda, hangi şeylerin özellik olması gerektiğine ve hangilerinin herşeyi karmaşıklaştıran yöntemlere (özellikle de yansıma kullanırsak!) Karar vermeliyiz.
Warbo

1
1. Fiziği saklamak her zaman çok iyi değildir. Benim yorumum softwareengineering.stackexchange.com/a/358662/44104 için bak . 2. Alıcı / alıcı yaratmanın ne kadar zor ya da basit olduğundan bahsetmiyorum. C # kesinlikle bahsettiğimiz aynı sorun var. Toplu bilgi yüklemesinin kötü bir çözümü nedeniyle kapsülleme eksikliği. 3. Evet, çözüm sözdizimine dayanıyor olabilir, ancak lütfen bahsettiğinizden farklı şekillerde. Bunlar kötü, burada açıklamalarla dolu büyük bir sayfa var. 4. Çözümün sözdizimine dayanmasına gerek yok. Java sınırlarında yapılabilir.
Gangnus

-1

Biri bana tüm alanları özel olarak gizlemenin ve bundan sonra hepsini ekstra bir teknolojiye maruz bırakmanın ne demek olduğunu açıklayabilir mi? O zaman neden sadece ortak alanları kullanmıyoruz? Sadece başlangıç ​​noktasına dönmek için uzun ve zor bir yol yürüdüğümüzü hissediyorum.

Evet, çelişkili. Önce Visual Basic'te özelliklere rastladım. O zamana kadar, diğer dillerde, benim deneyimim, tarlaların çevresinde mülk saran kimse yoktu. Sadece halka açık, özel ve korunan alanlar.

Özellikler bir tür kapsülleme idi. Açık alan ve hatta veri türünü gizlerken bir veya daha fazla alanın çıktısını kontrol etmenin ve kontrol etmenin bir yolu olduğunu, örneğin belirli bir formatta bir dize olarak bir tarih yayınladığının Visual Basic özelliklerini anladım. Fakat o zaman bile kişi daha büyük nesne perspektifinden "durumu gizleme ve işlevselliği ortaya koyma" değildir.

Ancak, mülkler ayrı mülk alıcıları ve belirleyicileri nedeniyle kendilerini haklı çıkarır. Özelliği olmayan bir alanı göstermek, tamamen ya da hiç değildi - eğer okuyabilseydiniz, onu değiştirebilirsiniz. Böylece, zayıf sınıf tasarımını korumalı ayarlayıcılarla haklı gösterebiliriz.

Öyleyse neden gerçek yöntemler kullanmıyoruz? Çünkü Visual Basic (ve VBScript ) (oooh! Aaah!), Kitleleri kodlayan (!) Ve tüm öfkesiydi. Ve böylece bir idiyotokrasi nihayet egemen oldu.


Evet, UI mülklerinin özel bir anlamı var, bunlar halka açık ve alanları güzel temsil ediyor. İyi bir nokta.
Gangnus

“Öyleyse neden gerçek yöntemleri kullanmadık?” Teknik olarak .Net versiyonunda yaptılar. Özellikleri alma ve ayarlama işlevleri için sözdizimsel şekerdir .
Pharap

"salaklık" ? " Özdeyiş " demek istemiyor musun ?
Peter Mortensen,

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.