Yanıtlar:
Statik üyeleri bir arayüze yerleştirmek (ve bu arayüzü uygulamak) kötü bir uygulamadır ve bunun için bir isim bile vardır, Sabit Arayüz Antipattern , bkz.Etkili Java , Madde 17:
Sabit arayüz modeli, arayüzlerin kötü kullanımıdır . Bir sınıfın bazı sabitleri dahili olarak kullandığı bir uygulama ayrıntısıdır. Sabit bir arabirim uygulamak, bu uygulama ayrıntısının sınıfın dışa aktarılan API'sine sızmasına neden olur. Sınıfın sabit bir arabirim uygulamasının bir sınıfın kullanıcıları için hiçbir önemi yoktur. Hatta kafalarını karıştırabilir. Daha da kötüsü, bir taahhüdü temsil eder: eğer gelecekteki bir sürümde sınıf, artık sabitleri kullanmaya gerek kalmayacak şekilde değiştirilirse, ikili uyumluluğu sağlamak için yine de arabirimi uygulamalıdır. Son olmayan bir sınıf sabit bir arabirim uygularsa, tüm alt sınıflarının ad alanları arabirimdeki sabitler tarafından kirletilir.
Java platform kitaplıklarında aşağıdaki gibi birkaç sabit arabirim vardır:
java.io.ObjectStreamConstants
. Bu arayüzler anormallik olarak görülmeli ve taklit edilmemelidir.
Sabit arayüzün bazı tuzaklarından kaçınmak için (çünkü insanların onu uygulamasını engelleyemezsiniz), özel kurucuya sahip uygun bir sınıf tercih edilmelidir (örnek Wikipedia'dan ödünç alınmıştır ):
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
Ve sabitlere tam olarak nitelendirmek zorunda kalmadan erişmek için (yani, sınıf adlarının önüne sınıf adı eklemek zorunda kalmadan), statik bir içe aktarma kullanın (Java 5'ten beri):
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
" Sabit arayüz modeli, arayüzlerin kötü kullanımıdır "
Bu hipotezi kim uydurmuşsa, ne kadar guru olursa olsun, onu kötü alışkanlıkları ve uygulamaları verimli bir şekilde uygulamaya devam etme ihtiyacı temelinde oluşturmuştur. Hipotez, kötü yazılım tasarım alışkanlıklarının geçerliliğinin teşvik edilmesine dayanmaktadır.
Bu hipoteze karşı bir cevap yazdım: Java'da sabitleri uygulamanın en iyi yolu nedir? bu hipotezin temelsizliğini açıklıyor.
Bu hipotezi haksız kılan gerekçelerimi yayınladıktan sonra 2 saat içinde kapanana kadar, bu soru 10 yıl boyunca açık kalmıştı ve bu yanlış yönlendirilmiş hipoteze yürekten bağlı olanların tartışmaya İSTİSMARLIĞINI ifşa ediyordu.
Bunlar hipoteze karşı ifade ettiğim noktalar
Bu hipotezi sürdürmenin temeli, kötü yazılım alışkanlıklarının ve metodolojilerinin etkileriyle başa çıkmak için yöntemlere ve KISITLAYICI kurallara ihtiyaç duyulmasıdır.
" Sürekli arayüz modeli, arayüzlerin kötü kullanımıdır " düşüncesini savunanlar, bu kötü alışkanlıkların ve uygulamaların etkileriyle başa çıkma ihtiyacının neden olduğu nedenler dışında herhangi bir neden sunamazlar.
Temel sorunu çözün.
Öyleyse neden kendi rahatınız için Java dil yapısının her dil özelliğini tam olarak kullanıp yararlanmıyorsunuz? Ceket Gerekmez. Neden etkisiz yaşam tarzınızı daha etkili yaşam tarzlarını ayırt etmek ve suçlamak için barikat kurmak için kurallar icat ediyorsunuz?
bilgi organizasyonudur. Sürece aracılık eden bilgi ve bu bilginin davranışı, mühendislikten veya sürece çözümler eklemeden önce, sözde iş kuralları ile birlikte anlaşılmalıdır. Bu tür bir bilgi organizasyonu yöntemi, birkaç on yıl önce veri normalizasyonu olarak adlandırıldı.
O zaman sadece bir çözümün mühendisliği mümkün olabilir çünkü bir çözümün bileşenlerinin tanecikliği ve modülerliğini, bilgi bileşenlerinin tanecikliği ve modülerliği ile hizalamak optimal stratejidir.
Bilgiyi organize etmenin önünde iki veya üç önemli engel vardır.
Veri modeli "normalleştirme" ihtiyacına yönelik algı eksikliği.
EF Codd'un veri normalleştirme konusundaki ifadeleri hatalı, kusurlu ve belirsizdir.
Çevik mühendislik kılığına giren en son moda, ilerideki modüllerin organizasyonunu planlamamalı ve koşullandırmamalı, çünkü ilerledikçe yeniden düzenleme yapabilirsiniz. Mazeret olarak gelecekteki keşiflerden etkilenmeden yeniden düzenleme ve sürekli değişim kullanılmaktadır. O zaman, kârları ve varlıklandırmayı geciktirmek için muhasebe hilelerinin kullanılmasıyla proses bilgilerinin davranışına ilişkin temel keşifler yapılır, bu nedenle temel bilgi ve bunların tedavisine şu anda ihtiyaç olmadığı kabul edilir.
Sırf geçici vur-kaç programlama alışkanlıklarınızı sevdiğiniz için kurallar koymayın veya ona karşı herhangi bir fetva yayınlamayın.
Silahı nasıl kullanacağını bilmeyen ya da silahı kötüye kullanma eğilimi gösteren insanlar olduğu için silah sahipliğini yasaklamayın.
Oluşturduğunuz kurallar, profesyonel olarak kodlama yapamayan acemileri programlamak için tasarlanmışsa ve kendinizi onların arasında sayıyorsanız, bunu söyleyin - fetvanınızın uygun şekilde normalleştirilmiş veri modelleri için geçerli olduğunu beyan etmeyin.
Kurucu babaların ABD Anayasası için ilk niyetlerinin ne olduğu umurumda değil. Yazılmamış kodlanmamış niyetler umrumda değil. Sadece yazılı Anayasa'da tam anlamıyla neyin kodlandığı ve toplumun etkin işleyişi için bunları nasıl kullanabileceğimle ilgileniyorum.
Yalnızca Java dili / platform özelliklerinin bana neye izin verdiğiyle ilgileniyorum ve yazılım çözümlerimi verimli ve etkili bir şekilde ifade etmem için bir ortam sağlamak için bunları sonuna kadar kullanmak niyetindeyim. Ceket gerekmez.
Parametreyi değere eşlemek için fazladan kod yazmayı gerektirir. Java'nın kurucularının sizin yazınız olmadan parametre-değer eşlemesi sağlamamış olması, eşleme kodunun Enum Sabitlerinin Java dilinin kasıtsız kullanımı olduğunu gösterir.
Özellikle parametrelerinizi normalleştirmeye ve bileşenleştirmeye teşvik edilmediğiniz için, bir Enum torbasına karıştırılan parametrelerin aynı boyuta ait olduğuna dair yanlış bir izlenim olacaktır.
Bunu unutma. Veri modelinizi tasarlayıp normalleştirdiyseniz ve bunlar sabitler içeriyorsa, bu sabitler sözleşmelerdir. Veri modelinizi normalleştirmediyseniz, bu kötü alışkanlıkla başa çıkmak için kısıtlayıcı kodlamanın nasıl uygulanacağı konusunda verilen fetvalara uymalısınız.
Bu nedenle, Arayüzler, Sabitler sözleşmesini uygulamanın mükemmel bir yoludur.
Evet. Herhangi biri istemeden herhangi bir arayüzü yanlışlıkla uygulayabilir. Bu kadar kasıtsız programcıların önüne hiçbir şey çıkmaz.
Anlaşılmamış / başıboş parametrelerin API'ye sızmasına neden olan varsayılan kötü uygulamaları korumak için kısıtlayıcı kararnameler koymayın. Suçu Arayüz Sabitlerine atmak yerine temel sorunu çözün.
Normal işleyen ve ETKİLİ bir programcı, su altında ne kadar kalabileceğini, kavurucu sıcağında veya yağışlı fırtınalarda ne kadar yürüyebileceğini kanıtlamak için orada değildir. Her gün işe 10 mil gitmek için araba, otobüs veya en azından bisiklet gibi verimli bir araç kullanacak.
Sırf IDE'siz programlamaya ezoterik bir çilecilik takıntınız olduğu için diğer programcılara kısıtlama koymayın.
OSGI böyle bir çerçevedir. Ve Arayüz Sabitleri aleyhindeki kararname de öyle.
Arayüz sabitleri, bir veri modelinin iyi tasarlanmış ve normalleştirilmiş bileşenlerini Sözleşme'ye yerleştirmenin etkili ve verimli bir yoludur.
Bir sınıf dosyasına yerleştirilmiş uygun şekilde adlandırılmış özel bir arabirimdeki arabirim sabitleri, tüm özel sabitlerinizi dosyanın her yerine dağıtmak yerine gruplamak için de iyi bir uygulamadır.
Bu eski soruyla birkaç kez karşılaştım ve kabul edilen cevap hala kafamı karıştırıyor. Çok düşündükten sonra, bu sorunun daha da açıklığa kavuşturulabileceğini düşünüyorum.
Sadece karşılaştırın:
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
vs
public interface Constants {
double PI = 3.14159;
double PLANCK_CONSTANT = 6.62606896e-34;
}
Aynı kullanım. Çok daha az kod.
Sanırım @Pascal Thivent'in cevabının yanlış vurgusu var, işte benim versiyonum:
Statik üyeleri bir arabirime koymak ( ve bu arabirimi uygulamak ) kötü bir uygulamadır.
Etkili Java'dan alıntı, sürekli arayüzün başkaları tarafından uygulandığı varsayımına sahiptir, ki bunun olmaması gerektiğini (ve olmayacağını) düşünüyorum.
Gibi bir adla sabit bir arayüz oluşturduğunuzda Constants
, hiç kimse tarafından uygulanmamalıdır. (teknik olarak mümkün olsa da, buradaki tek sorun budur)
Standart kütüphane, tasarımın herhangi bir olası kötüye kullanımını karşılayamaz, bu yüzden orada hiçbirini göremezsiniz.
Ancak yaklaşık endişe gerekmez, çünkü sabitler arayüzü kullanarak, normal geliştiricilerin günlük projeler için çok daha kolaydır static
, final
,empty constructor
vb ve herhangi kötü bir tasarım sorunu neden olacak DEĞIL. Aklıma gelen tek dezavantajı hala "arayüz" ismine sahip olması, ama bundan daha fazlası değil.
Sonunda sanırım herkes kitaplardan alıntılar yapıyor ve standlarına fikir ve gerekçeler veriyor. Benim için istisna yok. Belki de karar yine de her projenin geliştiricisine bağlıdır. Kendinizi rahat hissediyorsanız kullanmaya devam edin. Yapabileceğimiz en iyi şey, onu proje boyunca tutarlı hale getirmektir .
public
, bir arayüz olduğu için ihmal edilebilir, bu da onu basitçe yapar. double PI = 3.14159;
Kullanımı arayüzü Constants.PI
uygulamak için bunu kullanan sınıfa ihtiyaç duymaz Constants
! Arayüz yaklaşımının kullanım açısından çok daha temiz olduğunu düşünüyorum, IMHO
Joshua Bloch, "Etkili Java - Programlama Dili Kılavuzu":
Sabit arayüz modeli, arayüzlerin kötü kullanımıdır. Bir sınıfın bazı sabitleri dahili olarak kullandığı bir uygulama detayıdır. Sabit bir arabirim uygulamak, bu uygulama ayrıntısının sınıfın dışa aktarılan API'sine sızmasına neden olur. Sınıfın sabit bir arabirim uygulamasının bir sınıfın kullanıcıları için hiçbir önemi yoktur. Hatta kafalarını karıştırabilir. Daha da kötüsü, bir taahhüdü temsil eder: eğer gelecekteki bir sürümde sınıf, artık sabitleri kullanmaya gerek kalmayacak şekilde değiştirilirse, ikili uyumluluğu sağlamak için yine de arabirimi uygulamalıdır. Son olmayan bir sınıf sabit bir arabirim uygularsa, tüm alt sınıflarının ad alanları arabirimdeki sabitler tarafından kirletilir.
Arabirimi uygulayan sınıflarda kullanılacak ortak sabitleriniz varsa kullanışlıdırlar.
İşte bir örnek: http://www.javapractices.com/topic/TopicAction.do?Id=32
Ancak önerilen uygulamanın, arayüzlerde sabitler yerine statik içe aktarmalar kullanmak olduğunu unutmayın. İşte bir referans: http://www.javapractices.com/topic/TopicAction.do?Id=195
Çok yankılanan cevaplar var.
Ama bu soru hakkında bazı düşüncelerim var. (yanlış olabilir)
Bana göre, bir arayüzdeki alanlar tüm proje için sabit olmamalı, sadece arayüz için araçlar ve arayüzler onu genişletiyor ve bu arayüzleri uygulayan veya onlarla yakın ilişki içinde olan sınıflar. Global olmayan belirli bir aralıkta kullanılmaları gerekir.
Arayüzle ilgili iki nokta:
Bir arayüz, onu uygulayan bir nesnenin yapabileceklerinin bir alt kümesini tanımlar . (Bu sezgi)
Bir arayüz, onu uygulayan nesnelerin izlediği ortak sabitleri tanımlar .
Bu yüzden Sabitler Arayüzü global sabitler için kullanılmazsa , kabul edilebilir olduğunu düşünüyorum:
implements
onu (ve tabii ki, uygulamada bu ortak sabitleri kullanın).Misal:
interface Drawable {
double GOLDEN_RATIO = 1.618033988;
double PI = 3.141592653;
...
// methods
...
}
public class Circle implements Drawable {
...
public double getCircumference() {
return 2 * PI * r;
}
}
void usage() {
Circle circle = new Circle(radius: 3.0);
double maxRadius = 5.0;
if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
...
}
}
Bu örnekte:
Circle implements Drawable
, Circle
bunun muhtemelen içinde tanımlanan sabitlere uygun olduğunu hemen anlarsınız Drawable
, aksi takdirde iyi olanlardan daha kötü bir isim seçmeleri gerekir PI
ve GOLDEN_RATIO
zaten alınmışlardır!Drawable
nesneler belirli PI
ve GOLDEN_RATIO
tanımlanmış olana uygundur , farklı pi ve altın oran hassasiyetine sahip Drawable
olmayan nesneler olabilir Drawable
.javax.swing.SwingConstants
Arayüz salıncak sınıflar arasında kullanılan statik alanlar var bir örnektir. Bu, aşağıdaki gibi bir şeyi kolayca kullanmanızı sağlar
this.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
veya this.add(SwingComponents.LINE_START, swingcomponent);
Ancak bu arayüzün yöntemleri yok ...
Bu soruyla karşılaştım ve bahsedilmeyen bir şey ekleyeceğimi düşündüm. Genel olarak, buradaki Pascal'ın cevabına katılıyorum . Ancak, bir arayüzdeki sabitlerin "her zaman" bir anti-model olduğunu düşünmüyorum.
Örneğin, tanımladığınız sabitler o arayüz için bir sözleşmenin parçasıysa, arayüzün sabitler için harika bir yer olduğunu düşünüyorum. Bazı durumlarda, sözleşmeyi uygulamanızın kullanıcılarına ifşa etmeden parametrelerinizi özel olarak doğrulamak uygun değildir. Herkese açık bir sözleşme olmadan, kullanıcılar, sınıfı yeniden derlemeden ve kodunuzu okumadan sadece neyle doğruladığınızı tahmin edebilir.
Dolayısıyla, bir arabirim uygularsanız ve arabirim, sözleşmelerinizi sağlamak için kullandığınız sabitlere sahipse (örneğin, tamsayı aralıkları gibi), sınıfınızın bir kullanıcısı arabirimdeki sabitleri kontrol ederek arabirim örneğini doğru şekilde kullandıklarından emin olabilir. kendilerini. Sabitler uygulamanıza özel olsaydı veya uygulamanız pakete özel veya başka bir şey olsaydı bu imkansız olurdu.
Sınıflar arasında paylaşılan sabitlerle uğraşırken arayüz sabitlerini kullanıyorum.
public interface TestConstants
{
String RootLevelConstant1 = "RootLevelConstant1";
interface SubGroup1
{
String SubGroupConstant1 = "SubGroup1Constant1";
String SubGroupConstant2 = "SubGroup1Constant2";
}
interface SubGroup2
{
String SubGroupConstant1 = "SubGroup2Constant1";
String SubGroupConstant2 = "SubGroup2Constant2";
}
}
Gruplama, özellikle büyük bir sabit setiyle büyük bir varlıktır.
Kullanmak için onları birbirine zincirlemeniz yeterlidir:
System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);