接口只用於定義類型
當類實現接口時,接口就充當可以引用這個類的實例的類型(type)。因此,類實現了借口,就表明客戶端可以對這個類的實例實施某些動作。為了任何其他目的而定義接口是不恰當的。
有一種接口被稱為常量接口(constant interface),亞布媽祖上面的條件。這種接口沒有包含任何方法,它只包含靜態的final域,每個域都導出一個常量。使這些常量的類實現這個借口,以避免類名來修飾常量名。
// Constant interface antipattern - do not use
public interface PhysicalConstants{ // Avogadro's number
static final double AVOGADROS_NUMBER = 6.02214199e23; // Boltzmann constant
static final double BOLTZMANN_CONSTANT = 1.3806503e-23; //Mass of the electron
static final double ELECTRON_MASS = 9.109381883-31; }
常量接口模式是對接口的不良使用。類在內部使用某些變量,這純粹是實現細節。實現常量接口,這會導致把這樣的實現細節泄漏到該類的導出API中。類實現常量接口,這對於這個類的用戶來講並沒有什么價值。實際上,這樣做反而會使他們更加糊塗。更糟糕的是,它代表着一種承諾:如果將來版本中,這個類被修改了,它將不再需要這些常量了,它依然必須實現這個接口,以確保二進制兼容性。如果非final類實現了常量接口,它的所有類的命名空間也會被接口中的常量所“污染”。
在Java平台類庫中有幾個常量接口,例如java.io.ObjectStreamConstants。這些接口應該被認為反面的典型,不值得效仿。
如果到出常量,可以有集中合理的選擇方案。如果這些常量與某個相關的類或者接口緊密相關,就應該把這些常量添加到這個類或者接口中。例如Java平台類庫中所有的數值包裝類,如Integer和Double,都導出了MIN_VALUE和MAX_VALUE常量。如果這些常量被看成枚舉類型的成員,就應該用枚舉類型(enum type)來導出這些常量。否則應該使用不可實例化的工具類來導出這些常量。
// Constant utility class
public class PhysicalConstants{ private PhysicalConstants(){} // Avogadro's number
public static final double AVOGADROS_NUMBER = 6.02214199e23; // Boltzmann constant
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23; //Mass of the electron
public static final double ELECTRON_MASS = 9.109381883-31; }
工具類通常要求客戶端要用類名來修飾這些常量名,例如PhysicalConstants.AVOGADROS_NUMBER。如果大量利用工具類導出的常量,可以通過利用靜態導入(static import)機制,避免用類名來修飾常量名,不過靜態導入機制是Java發行版本1.5中才引入的。
簡而言之,接口應該只被用來定義類型,他們不應該被用來導出常量。