Özel alıcılar yerine kamu finalini kullanmak


51

Bu şekilde yazılmış çoğu değişmez POJO'yu görüyorum:

public class MyObject {
    private final String foo;
    private final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }

    public String getFoo() {
        return foo;
    }

    public int getBar() {
        return bar;
    }
}

Yine de onları bu şekilde yazmaya meyilliyim:

public class MyObject {
    public final String foo;
    public final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }
}

Referansların nihai olduğuna dikkat edin, bu nedenle Nesne hala değişmez. Daha az kod yazmama izin veriyor ve daha kısa (5 karakter: getve ()) erişimine izin veriyor .

Görebildiğim tek dezavantaj getFoo(), çılgınca bir şey yapmak için yolun aşağısındaki uygulamasını değiştirmek isteyip istemediğinizdir . Fakat gerçekçi olarak, bu asla gerçekleşmez, çünkü Nesne değişmezdir; örnekleme sırasında doğrulayabilir, örnekleme sırasında değişmez savunma kopyaları oluşturabilir ( ImmutableListörneğin Guava'nın bakınız ) ve fooveya barnesneye getçağrı için hazır olun .

Kaybettiğim herhangi bir dezavantaj var mı?

DÜZENLE

Sanırım eksik olduğum başka bir dezavantaj ise getveya ile başlayan yöntemlere yansıma kullanan serileştirme kütüphaneleri is, ama bu oldukça korkunç bir uygulama ...


Ne oluyor be? finaldeğişkeni nesneyi değişmez yapmaz. Normalde finalgeri arama oluşturmadan önce alanları tanımladığım bir tasarım kullanıyorum, böylece geri arama bu alanlara erişebiliyor. Elbette, herhangi bir setXyöntem dahil tüm yöntemleri çağırabilir .
Tomáš Zato

@ TomášZato Orada hiçbir setx yöntemleridir String, intya MyObject. İlk versiyonda, finalsadece sınıf içindeki yapıcıdan başka yöntemlerin denenmemesini sağlamaktır bar = 7;. İkinci versiyonda, finalyapmaktan tüketicilerin önlemek için gereklidir: MyObject x = new MyObject("hi", 5); x.bar = 7;.
Cory Kendall

1
Eh, " Referansların nihai olduğuna dikkat edin, öyleyse Objecthala değişken değil. " Yanıltıcıdır - öyle görünüyor ki herhangi final Objectbirinin değişmez olduğunu düşünüyorsunuz , ki bu değil. Yanlış anlaşılma için üzgünüm.
Tomáš Zato

3
Altta yatan değerler değişken olsaydı, özel + erişimciler yolu da bunu engellemezdi - myObj.getFoo().setFrob(...).
Beni Cherniavsky-Paskin

Yanıtlar:


38

Aklıma gelen dört dezavantaj:

  1. Aynı varlık için salt okunur ve değişken bir forma sahip olmak istiyorsanız, ortak bir örüntü, yalnızca korunan üye değişkenleriyle erişimcileri ortaya çıkaran, sonra onu genişleten ve ayarlayıcıları ekleyen bir MutableEntity oluşturmak için değişmez bir sınıf Varlığına sahip olmaktır. Sürümünüz bunu önler.
  2. Alıcıların ve ayarlayıcıların kullanımı, JavaBeans konvansiyonuna bağlı kalmaktadır. Sınıfınızı JSTL veya EL gibi mülk tabanlı teknolojilerde bir fasulye olarak kullanmak istiyorsanız, kamu alıcılarını ortaya çıkarmanız gerekir.
  3. Değerleri türetmek veya veritabanına bakmak için uygulamayı değiştirmek istiyorsanız, müşteri kodunu yeniden gözden geçirmeniz gerekir. Bir erişimci / mutator yaklaşımı sadece uygulamayı değiştirmenize izin verir.
  4. En az şaşkınlık - genel örnek değişkenleri gördüğümde, hemen kimin mutasyona uğradığını görebilirim ve kapsülleme kaybolduğu için pandora'nın kutusunu açacağım için endişeleniyorum. http://en.wikipedia.org/wiki/Principle_of_least_astonishment

Bu, sürümünüzün kesinlikle daha özlü olduğunu söyledi. Bu, yalnızca belirli bir paket içinde kullanılan özel bir sınıfsa (belki paket kapsamı burada iyi bir fikir olabilir), o zaman bunu bir kereye mahsus olmak üzere düşünebilirim. Ancak büyük API'leri bu şekilde ifşa etmem.


3
Harika cevaplar; Bazıları ile anlaşmazlıklar var ama bu sitenin tartışma için en iyi forum olduğundan emin değilim. Kısacası, 1) Değişmez olduğunu düşündükleri değişebilir formu kullanarak başkalarını kırabilirim (belki örneklerimde sınıfa son vermeliyim), 2) Katılıyorum, 3) Artık bunun bir POJO olmadığını savunuyorum. case, 4) Şimdilik hemfikirim, ama umarım böyle tartışmalar en az şaşırtıcı olanı değiştirebilir :).
Cory Kendall

2
5) Kendiliğinden değişebilen sınıfları / türleri - benzer dizileri güvenle maruz bırakamazsınız. Güvenli yol, bir alıcıdan bir kopyasını her defasında döndürmektir.
Clockwork-Muse,

@ Clockwork-Muse, insanların aptal olmadığını varsayarsanız yapabilirsiniz. SomeObj.thisList.add () öğesine erişirken, diğer bazı nesneler durumunu değiştirdiğiniz açıktır. SomeObj.getThisList (). Add () ile bilinmemektedir. Belgeleri sormanız veya kaynağa bakmanız gerekir, ancak yalnızca yöntem bildiriminde bunu söylemek mümkün değildir.
kritzikratzi

2
@kritzikratzi - Sorun şu ki, kodunuzun aptallara çarpmayacağını garanti edemezsiniz. Bir noktada olacak (hatta kendisi bile sona erebilir!) Ve sürpriz çok büyük bir sorun olabilir.
Clockwork-Muse

1
Eh, herhangi bir değişken tipin değişmez tipten miras kalmasına izin vermek doğal olarak yanlış. Değişmez bir türün "Ben değişmiyorum. Hiç." Garantisi verdiğini unutmayın.
Deduplicator

26

Alıcılardan / ayarlayıcılardan da kurtulun ve iyisiniz!

Bu, Java programcıları arasında oldukça tartışmalı bir konudur.

Her neyse, alıcıların / ayarlayıcıların (!) Yerine genel değişkenleri kullandığım iki durum var:

  1. kamu finali Bana göre bu bir alıcıdan çok daha iyi "ben değişmezim" diye işaret ediyor. Çoğu IDE, otomatik tamamlama sırasında son değiştiriciyi 'F' ile gösterecektir. Alıcıların / ayarlayıcıların aksine, bir setXXX'in yokluğunu aramanız gereken yer.
  2. kamuya açık olmayan nihai veri sınıfları için bunu seviyorum. Ben sadece tüm alanları kamuya açıyorum. Alıcı, kurucu, kurucu yok. Hiçbir şey yok. Bir pojodan daha az. Bana göre bu derhal "bak, aptalım. Veri tutarım, hepsi bu. İçime doğru verileri koymak SİZİN işi" diye işaret ediyor. GSON / JAXB / vb. Bu sınıfları iyi idare et. Onlar yazmak için mutluluktur. Amaçları veya yetenekleri hakkında hiç şüphe yok. Ve en önemlisi: Bir değişkeni değiştirdiğinizde hiçbir yan etkisinin olmadığını biliyorsunuz. IMHO bu, çok az belirsizliğe sahip çok özlü veri modelleriyle sonuçlanırken, alıcılar ve belirleyiciler bazen sihirlerin içinde gerçekleştiği bu büyük problemi yaşarlar.

5
Biraz aklı başında bir akıl sağlığını görmek güzel :)
Navin

2
Modelinizin geliştiği gün gelene kadar ve eski alanlardan biri şimdi diğerinden türetilebilir. Geriye dönük uyumluluğu korumak istediğiniz için eski alanın kalması gerekir, ancak yalnızca alıcı ve ayarlayıcı kodunu değiştirmek yerine, bu eski alanın yeni model gösterimini izlemesini sağlamak için kullanıldığı her yerde değiştirmek zorunda kalırsınız. Yazması kolay .. evet elbette ... uzun vadede sürdürmek için kabus ... Bu yüzden alıcı / ayarlayıcı veya daha iyisi hala C # özellik erişimcilerinde.
Newtopian,

9

Layman'ın sözleriyle:

  • Birkaç kod satırı kaydetmek için enkapsülasyonu ihlal ediyorsunuz . OOD'un amacını yendi.
  • Müşteri kodunun, sınıf üyelerinizin isimleri ile birleştirilmesi zor olacaktır . Bağlama kötüdür. OOD'un tüm amacı kuplajı önlemektir.
  • Ayrıca sınıfınızın asla değişken olması gerekmeyeceğinden de eminiz . Her şey değişir. Değişim, sabit olan tek şeydir.

6
Bu nasıl bir kapsülleme ihlalidir? Her iki sürüm de birbirleriyle olduğu gibi dış dünyaya da açıktır (salt okunur erişim ile). Değişimin sert birleşimi ve esnekliği konusunda haklısınız, ancak bunu tartışmayacağım.
KChaloux,

4
@KChaloux "Kapsülleme ihlali" ni "derleme hatası olan ve bunu düzeltmek için zaman kaybetmek zorunda" koduyla karıştırıyorsunuz, ilk önce siz olun. İkincisi daha sonra olur. Açıklığa kavuşturmak için: kapsülleme halihazırda zaten ihlal edilmiştir. Sınıfınızın iç kısımları günümüzde artık kapsüllenmemektedir. Ancak, gelecekteki sınıf değişirse, gelecekte kapsülleme kırıldığı için müşteri kodu gelecekte kırılacaktır. Kapsülleme eksikliği nedeniyle iki farklı "son" vardır, bugün kapsülleme, yarın müşteri kodu.
Tulains Córdova

8
Teknik olarak, getters / etc kullandığınızda İstemci kodu, bunun yerine yöntem adlarına zorlanacaktır. Eski kütüphanelerin "kullanımdan kaldırılmış" etiketi / ek açıklamasına sahip eski sürüm sürümlerini içermesi gerektiğine bakın, çünkü eski kod hala bunlara bağlı Bunu yapmak gerekiyordu).
JAB

5
Pragmatik: Programcılar kamu alıcılarını / belirleyicilerini yeniden adlandırmadan özel alan adlarını gerçekte ne sıklıkta görürler? Söyleyebileceğim kadarıyla, onları aynı şekilde isimlendirmek için topluluk çapında bir kongre var, bu kongre sadece alan adlarından alıcılar ve belirleyiciler üreten IDE araçlarının bir sonucu olsa bile. Teorik: Nesne yönelimli bir modelleme perspektifinden bakıldığında, kamuya açık olan her şey kamu sözleşmesinin bir parçasıdır, iç uygulama detayı değildir. Öyleyse eğer birisi son bir alanı kamuya açmaya karar verirse, bunun yerine getirmeyi taahhüt ettikleri sözleşme olduğunu söylemiyorlar mı?
Thomas Jung

3
@ user949300 Hangisini öğreneceğimi söyle.
Tulains Córdova

6

Kesin olarak görebildiğim olası bir dezavantaj, sınıftaki verilerin iç temsiline bağlı olmanızdır. Bu muhtemelen çok büyük bir şey değil, ancak ayarlayıcıları kullanırsanız ve foo ve bar'ın başka bir yerde tanımlanmış başka bir sınıftan döndürülmesine karar verirseniz, MyObject kullanan sınıfların değişmesi gerekmeyecektir. Sadece MyObject'e dokunmanız gerekir. Ancak, eğer çıplak değerleri kullanırsanız, o zaman MyObject'in kullandığım her yere dokunmanız gerekir.

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.