Java koleksiyonları neden arayüzde "isteğe bağlı yöntemlerle" uygulandı?


69

Java koleksiyon çerçevesini genişleten ilk uygulamam sırasında, koleksiyon arayüzünün isteğe bağlı olarak bildirilen yöntemler içerdiğini görmekten çok şaşırdım. Uygulayıcının desteklenmiyorsa UnsupportedOperationExceptions atması bekleniyor. Bu hemen bir zayıf API tasarım seçimi olarak beni vurdu.

Joshua Bloch'un mükemmel "Etkili Java" kitabının çoğunu okuduktan ve daha sonra bu kararlardan sorumlu olabileceğini öğrendikten sonra, kitapta yer alan ilkelere uymuyor gibi görünüyordu. İki arabirim bildirmeyi düşünüyorum: Koleksiyon ve "isteğe bağlı" yöntemlerle Koleksiyon'u genişleten Koleksiyon ve MutableCollection, daha fazla bakım gerektirebilir müşteri koduna yol açacaktı.

Buradaki sorunların mükemmel bir özeti var .

İki arabirim uygulaması yerine isteğe bağlı yöntemlerin seçilmesinin iyi bir nedeni var mıydı?


IMO, iyi bir sebep yok. C ++ STL, 80'li yılların başlarında Stepanov tarafından oluşturuldu. Kullanılabilirliği garip C ++ şablon sözdizimi ile sınırlı olmasına rağmen, Java koleksiyonu sınıflarıyla karşılaştırıldığında tutarlılık ve kullanılabilirlik paragonudur.
kevin cline

Java için bir C ++ STL 'taşıma' vardı. Ancak sınıf sayısında 5 kat daha büyüktü. Bu zihinle, daha büyük olanın daha tutarlı ve kullanışlı olduğunu satın almıyorum. docs.oracle.com/javase/6/docs/technotes/guides/collections/…
m3th0dman

@ m3th0dman Java'da çok daha büyük çünkü Java'nın C ++ şablonlarına eşdeğer bir gücü yok.
kevin cline

Belki de geliştirdik sadece bazı garip tarzı, ama benim kod "salt okunur" olarak tüm koleksiyonları tedavi etmek eğilimindedir, (daha doğrusu sen saymak veya hangi üzerinde size yineleme sadece bir şey) dışında için birkaç aslında koleksiyon oluşturmak yöntemlerle. Zaten muhtemelen iyi bir uygulama (özellikle eşzamanlılık için). Ve bu kadar çok şikayetçi olan isteğe bağlı yöntemler benim için hiçbir zaman gerçek bir sorun olmadı . Jenerics'in "süper" ve "uzayan" kabusları da bir konunun konusu değildi. Sadece başkalarının bu genel uygulamayı kullanıp kullanmadığını merak etmek
user949300

Yanıtlar:


28

SSS cevap verir. Kısacası, değiştirilebilen, değiştirilemez görünüm, sadece sil, sadece eklenti, sabit uzunluklu, değiştirilemez (diş çekme için) ve benzeri olası seçenek seçeneklerinin her biri için gerekli arayüzlerin potansiyel birleşimsel patlamasını gördüler.


6
Java, constC ++ gibi bir anahtar kelimeye sahip olsaydı, bunların hepsinden kaçınılırdı .
Etienne de Martel

@Etienne: Daha iyi Python gibi metaclasses. Daha sonra programsal olarak birleştirici arabirim sayısını oluşturabilirsiniz. Const ile sorun, sadece size bir veya iki boyutu sağlamasıdır: vector<int>, const vector<int>, vector<const int>, const vector<const int>. O zaman grafikleri uygulayarak deneyin ve grafik yapısı sabit yapmak istiyorum ama düğüm vb değiştirilebilir niteliklerini Şimdiye kadar iyi, ama
Neil G

2
@Etienne, yapılacaklar listemde "Scala Learn" ü yükseltmek için bir neden daha!
glenviewjeff

2
Anlamadığım şey, neden canbir operasyon mümkün olursa test edecek bir yöntem yapmadılar. Arayüzü basit ve hızlı tutar.
Mehrdad

3
@Etienne de Martel Nonsense. Kombinatoryal patlamaya nasıl yardımcı olabilir?
Tom Hawtin - Tackline

10

Bana Interface Segregation Principle, şimdi olduğu kadar iyi keşfedilmemiş gibi geliyor; böyle şeyler yapmanın yolu (yani arayüzünüz tüm olası işlemleri içerir ve ihtiyacınız olmayanlar için istisnalar ortaya koyan "yozlaşmış" yöntemlere sahipsiniz), SOLID ve ISP kalite kodu için fiili standart haline gelmeden önce popülerdi.


2
Neden bir aşağı oy? Birisi ISS'yi sevmiyor mu?
Wayne Molina

Ayrıca, varyansı destekleyen çerçevelerde, temelde değişmez olanlardan kovariant veya çelişkili olabilen bir arayüzün bu yönlerini ayırmada BÜYÜK bir avantaj olduğunu belirtmekte fayda var. Bu tür bir destek olmasa bile, tür silme kullanmayan çerçevelerde, türden bağımsız olan bir arabirimin ayrıştırma yönlerinde değer söz konusudur (örneğin, Counthangi tür öğeleri içerdiği hakkında endişelenmenize gerek kalmadan bir koleksiyonun koleksiyonunu elde etmesine izin vermek ), ancak Java gibi tür silme tabanlı çerçevelerde bu böyle bir sorun değil.
supercat,

4

Bazı insanlar "isteğe bağlı yöntemler" den nefret ederken, çoğu durumda yüksek düzeyde ayrılmış arayüzlerden daha iyi anlambilim sunabilirler. Diğer şeylerin yanı sıra, bir nesnenin yaşamı boyunca yetenek veya özellik kazanması ya da bir nesnenin (özellikle sarıcı nesne) ne zaman hangi yetenekleri rapor etmesi gerektiğini bilmediği ihtimallerine izin verir.

Java koleksiyon sınıflarına iyi tasarım paragonlarını pek çağıracak olsam da, iyi bir koleksiyonlar çerçevesinin temelinde , özellikleri ve yetenekleri hakkında bir koleksiyon sorma yolları ile birlikte çok sayıda isteğe bağlı metot içermesi gerektiğini öneririm . Böyle bir tasarım, altta yatan koleksiyonun sahip olabileceği kabiliyetleri engellemeden tek bir sarmalayıcı sınıfının çok çeşitli koleksiyonlarla kullanılmasına izin verecektir. Yöntemler isteğe bağlı olmasaydı, koleksiyonların destekleyebileceği özelliklerin her birleşimi için farklı bir sarmalayıcı sınıfının olması ya da bazı durumlarda bazı sarmalayıcıların kullanılamaz olması gerekirdi.

Örneğin, bir koleksiyon bir öğeyi dizine göre yazmayı veya sonunda öğe eklemeyi destekliyorsa, ancak ortadaki öğeleri eklemeyi desteklemiyorsa, bunun üzerinde gerçekleştirilen tüm eylemleri günlüğe kaydedecek bir paketleyiciye kapsüllemek isteyen kod bir sürüme ihtiyaç duyacak Desteklenen yeteneklerin tam bir kombinasyonunu sağlayan veya hiçbiri mevcut değilse, günlüğe kaydetme paketleyicisinin ya eklenmiş ya da indeks yazmış ya da ikisini birden desteklemeyen bir sarıcı kullanması gerekirdi. Bununla birlikte, birleşik bir toplama arayüzü, üç yöntemi de "isteğe bağlı" olarak sağladıysa, ancak isteğe bağlı yöntemlerden hangisinin kullanılabileceğini belirten yöntemler içeriyorsa, tek bir sarmalayıcı sınıfı, herhangi bir özellik kombinasyonunu uygulayan koleksiyonları kaldırabilir. Hangi özellikleri desteklediği sorulduğunda, bir sarmalayıcı, kapsüllenmiş koleksiyonun desteklediği her şeyi yalnızca rapor edebilir.

"İsteğe bağlı yeteneklerin" varlığının bazı durumlarda toplanmış koleksiyonların, yeteneklerin uygulamaların varlığıyla tanımlanması durumunda mümkün olacağından çok daha etkili şekilde bazı işlevlerin uygulanmasına izin verebileceğini unutmayın. Örneğin, iki concatenateyöntemden oluşan karma bir koleksiyon oluşturmak için bir yöntemin kullanıldığını varsayalım . Bunlardan ilki 1.000.000 elementten oluşan bir ArrayList'tir ve sonuncusu yalnızca baştan itibaren yinelenebilen yirmi elementli bir koleksiyondu. Kompozit koleksiyona 1.000.013. Elementten (endeks 1.000.012) istendiyse, ArrayList'e kaç tane madde içerdiğini (yani 1.000.000) sorabilirdi, bunu istenen dizinden çıkar (12'ye kadar), ikinci on iki elementi oku ve atla toplama ve sonra bir sonraki öğeye dönün.

Böyle bir durumda, kompozit koleksiyonun bir maddeyi indeksle geri döndürme anında bir yolu olmasa da, kompozit koleksiyonun 1.000.013. Maddeden istenmesi, ondan 1.000.013 maddeyi tek tek okumak ve sonuncusu yok saymaktan çok daha hızlı olacaktır. bir.


@kevincline: Alıntı yapılan ifadeye katılmıyor musunuz? Arabirim uygulamalarının temel özelliklerini ve yeteneklerini, çoğu zaman dikkat çekmese de, arabirim tasarımının en önemli yönlerinden biri olarak tanımlayabilecekleri araçların tasarımını dikkate alırdım. Bir arabirimin farklı uygulamaları belirli ortak görevleri yerine getirmenin farklı en uygun yollarına sahipse, önemli olacağı senaryolarda en iyi yaklaşımı seçmek için performansı önemseyen müşteriler için bir araç olmalıdır.
Süperkat

1
üzgünüm, tamamlanmamış yorum. “'Bir koleksiyon sorma yolları' ... '' çalışma zamanı için bir derleme zamanı kontrolü olması gerektiğini harekete geçirmek üzereydi.
kevin cline

@kevincline: Müşterinin belirli bir yeteneğe sahip olması ve onsuz yaşayamaması gereken durumlarda derleme zamanı kontrolleri yardımcı olabilir. Öte yandan, koleksiyonların, derleme zamanı garantili olabileceklerinin ötesinde yeteneklere sahip olabileceği birçok durum vardır. Bazı durumlarda, sözleşmesi, türetilmiş arabirimin tüm yasal uygulamalarının , temel arabirimde isteğe bağlı olan belirli yöntemleri desteklemesi gerektiğini, ancak kodun bir şeyi işleyip işlemeyebileceği durumlarda desteklemesi gerektiğini belirten türetilmiş bir arabirime sahip olmak mantıklı gelebilir. bazı özelliklere sahip ...
supercat

... ancak var olan özelliğinden faydalanacaktır, kodun nesneye özelliği destekleyip desteklemediğini sorması daha iyi olur; bu, tip sistemine, nesnenin tipinin özelliği desteklemeyi vaat edip etmediğini sormasıdır. Belirli bir "spesifik" arayüz yaygın olarak kullanılacaksa, AsXXXtemel arayüzde, bu arayüzü uygularsa çağrıldığı nesneyi döndürecek, mümkünse o arayüzü destekleyen bir sarmalayıcı nesnesi döndürecek veya atacak şekilde bir yöntem içerebilir değilse bir istisna. Örneğin, bir ImmutableCollectionarayüz sözleşme gerektirebilir ...
supercat

2
Önerinizle ilgili bir sorun var: Bir nesnenin yetenekleri kullanım ömrü boyunca değişebiliyorsa, "sor o zaman yap" deseninde eşzamanlılık sorunu vardır. (Yine de bir istisna riske atmanız gerekiyorsa, sormaya zahmet
etmeyebilirsiniz

-1

O zamanlar daha iyi bilmeden, orijinal geliştiricilere bağlardım. 1998'den beri Java 2 ve Koleksiyonlar ilk piyasaya çıktığından beri OO tasarımında uzun bir yol kat ettik. Açıkça kötü tasarım gibi görünen şey, OOP'un ilk günlerinde çok açık değildi.

Ancak, fazladan dökümü önlemek için yapılmış olabilir. İkinci bir arayüz olsaydı, koleksiyon örneklerinizi aynı zamanda çirkin olan isteğe bağlı yöntemleri denemek için kullanmanız gerekirdi. Şimdi olduğu gibi hemen bir UnsupportedOperationException'ı yakalar ve kodunuzu düzeltirsiniz. Ancak iki arayüz olsaydı, her yerde anı ve döküm kullanmak zorunda kalacaktınız. Belki de geçerli bir değişimin olduğunu düşünüyorlardı. Ayrıca Java'nın 2 gün öncesine geri döndüğünde, düşük performans nedeniyle ağır bir şekilde kaşlarını çattı, aşırı kullanımı engellemeye çalışıyor olabilirlerdi.

Tabii ki tüm bunlar vahşi bir spekülasyondur, orijinal koleksiyonlardan birisinin çanları çalmadığı sürece, kesin olarak cevaplayabileceğimizden şüpheliyim.


7
Hangi döküm? Bir yöntem a a Collectiondeğil a döndürürse MutableCollection, değiştirilmemesi gerektiği açık bir işarettir. Neden birisinin onları yayınlamaya ihtiyacı olduğunu bilmiyorum. Ayrı arayüzlere sahip olmak, çalışma zamanında bir istisna almak yerine derleme zamanında bu tür hataları elde edeceğiniz anlamına gelir. Hatayı ne kadar erken alırsanız, o kadar iyi.
Etienne de Martel

1
Bu, daha az esnek olduğundan, koleksiyon kütüphanesinin en büyük yararlarından biri, yüksek seviye arayüzleri her yere geri döndürebileceğiniz ve gerçek uygulama için endişelenmeyeceğinizdir. İki arayüz kullanıyorsanız, şimdi daha sıkı bir şekilde bağlandınız. Çoğu durumda sadece Listeye dönmek istersiniz ve ImmutableList'i değil, genellikle bunu belirlemek için çağıran sınıfa bırakmak istediğinizde.
Jberg

6
Size salt okunur bir koleksiyon verirseniz, değiştirilmesini istemiyorum çünkü. Bir istisna atmak ve dokümantasyona güvenmek bir yama gibi çok can sıkıcıdır. C ++ 'da, constnesneyi değiştirilemediğini anında kullanıcıya söyleyerek basitçe bir nesne döndürürdüm .
Etienne de Martel

7
1998 "OO tasarımının ilk günleri" değildi.
quant_dev
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.