Press "Enter" to skip to content

Effective Java Madde 22: Arayüzleri Sadece Tür Tanımlamak İçin Kullanın

Bir sınıf bir arayüzü uyguladığı zaman, arayüz bu sınıftan oluşturulan nesneler için bir ”tür” olarak kullanılabilir. Bu sayede sınıfı kullanan bir istemci, sınıfı bir arayüz referansı ile temsil ederek arayüzdeki işlevlere erişebilir. Böylece istemciler sınıfın yapabilecekleri konusunda fikir edinmiş olur. Arayüzleri bu amaç dışında kullanmak uygun değildir.

Bu tarz uygun olmayan kullanımlara verilebilecek bir örnek, içerisinde static final alanlar kullanarak sabit değerlerin tanımlandığı, hiçbir metot içermeyen arayüzlerdir. Burada tanımlı sabit değerleri kullanan sınıflar da, bu değerlere erişirken arayüzün adını yazmamak için onu uygularlar. İşte bir örnek:

// Arayüzlerin yanlış kullanımına bir örnek
public interface PhysicalConstants {
    // Avogadro sayısı (1/mol)
    static final double AVOGADROS_NUMBER   = 6.022_140_857e23;

    // Boltzmann sabiti (J/K)
    static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;

    // elektronun kütlesi (kg)
    static final double ELECTRON_MASS      = 9.109_383_56e-31;
}

Bu arayüzlerin yanlış kullanımına bir örnek olarak verilebilir. Bir sınıfın belirli sabitleri kullanıyor olması bir gerçekleştirim detayıdır. Sınıfın böyle bir arayüzü uygulaması, kullandığı sabit değerlerin dışarıya sızması anlamına gelir. Böyle bir arayüzün uygulanıyor olmasının, sınıfı kullanan istemciler açısından hiçbir önemi olmadığı gibi kafa karışıklığı da yaratır. Daha da kötüsü, ileride sınıfta bir değişiklik yapılır ve bu sabit değerlere ihtiyaç kalmazsa, ikili uyumunu (binary compatibility) koruyabilmesi için arayüzü uygulamaya devam etmesi gerekecektir. final tanımlanmamış bir sınıf böyle bir arayüzü uygularsa, ondan kalıtılan çocuk sınıfların hepsinin isim uzayları (namespace) sabit değerler yüzünden kirlenecektir.

Not: Yukarıda bahsi geçen binary compatibility kavramına aşina olmayanlar için açıklama gereği hissettim. Burada aslında söylenmek isteneni anlamak için farzedelim ki elimizde yukarıdaki gibi sadece sabit değerleri tutan bir arayüz, bu arayüzü uygulayan bir sınıf ve bu sınıfı kullanan bir istemci olsun. Siz bu durumda sınıfı değiştirip arayüzü artık uygulamaz hale getirirseniz, bu sınıfı yeni haliyle derledikten sonra aynı istemci kodunu kullanamazsınız çünkü sınıfı artık tanımayacaktır. İstemciyi de tekrar derledikten sonra durum düzelecektir.

Daha detaylı bilgi isteyenler için: http://codefhtagn.blogspot.com/2010/11/java-binary-compatibility-more-than.html

Java kütüphaneleri içerisinde bu hatayı yapan java.io.ObjectStreamConstants gibi arayüzler bulunsa da, bunlar bir bozukluk olarak görülmeli ve taklit edilmemelidir.

Eğer yapmak istediğiniz sabit değerler tanımlayıp dışa açmaksa, kullanabileceğiniz birkaç tane mantıklı yaklaşım vardır. Eğer bu sabitler bir sınıfa veya arayüze özgüyse, bunları sınıf veya arayüz içerisinde tanımlamalısınız. Örneğin, Integer ve Double gibi sınıflar MIN_VALUE ve MAX_VALUE sabit değerlerini public static final alanlar olarak dışa açmışlardır. Eğer bu sabitler en iyi enum türleri ile ifade edilebiliyorsa o zaman enum olarak tanımlanmalıdırlar. (Madde 34) Aksi durumda ise nesnesi yaratılamayan bir yardımcı sınıf içerisinde tanımlanabilirler. (Madde 4) Aşağıda bunun bir örneğini görüyoruz:

// Yardımcı sınıf
package com.effectivejava.science;

public class PhysicalConstants {
    private PhysicalConstants() { }  // Nesne yaratılamaz!

    public static final double AVOGADROS_NUMBER = 6.022_140_857e23; 
    public static final double BOLTZMANN_CONST = 1.380_648_52e-23; 
    public static final double ELECTRON_MASS = 9.109_383_56e-31;
}

Burada numerik değerler yazılırken kullanılan alt çizgi (_) karakteri Java 7 ile beraber dile eklenmiştir. Bunlar sayıların anlamlarını etkilemeden okuma kolaylığı olması açısından kullanılmaktadır. 5 veya daha fazla rakamdan oluşan bu gibi numerik değerleri tanımlarken kullanılması önerilmektedir.

Yukarıdaki gibi bir yardımcı sınıftaki sabitleri kullanmak isteyen bir istemci, sınıfın adı ile beraber sabit değişkenini belirtmelidir, örneğin, PhysicalConstants.AVOGADROS_NUMBER. Eğer bu sabitleri sıklıkla kullanıyorsanız, static import kullanarak sınıf adını kullanmaktan kurtulabilirsiniz.

// Sınıf adını kullanmadan sabit değerlere erişmek için 
// static import kullanımı
import static com.effectivejava.science.PhysicalConstants.*;

public class Test {
    double atoms(double mols) {
        return AVOGADROS_NUMBER * mols;
    }
    ...

// PhysicalConstants sınıfından çok sayıda sabit değer kullanıyorsanız
// static import kullanmanızda sakınca yoktur.
}

Özetle, arayüzler sadece tür tanımlamak için kullanılmalıdır, sabit değerler tanımlamak için değil.

Share

Leave a Reply

%d bloggers like this: