优先使用接口而不是类

探讨《Effective Java》中关于优先使用接口而非类的原则。通过具体示例分析何时应选择类而非接口,尤其是在需要调用多个接口方法的情况下。

正在研读Joshua Bloch的《Effective Java》一书。书中至少在两条中提到了“优先使用接口而不是类”,一是第25条中的“参数类型优先使用接口而不是类”;另一个是第34条中的“通过接口引用对象”。

 

两条中所提及的例子一个是Map,一个是List(因为此书的作者就是Collection Framwork的作者)

 

Map ht = new Hashtable();

 

String value= doSomething(ht);

 

private String doSomething(Map pram) {

    .....

    // 比如这里需要 pram.clone(); 该怎么办呢?

    Map pram2 = pram.clone();   // 会出错的,因为Map接口中没有clone方法,那是Cloneable接口中的

}

 

 

书上说“没有理由在编写一个方法时使用Hashtable作为输入,相反,应该使用Map”。

 

但是我想问的是:一个类可能实现多个接口,如果不同接口中所定义的方法,都要用到,那么该选择哪个接口作为“代表”呢?恐怕哪个都是片面的。比如,如果我要在方法对传入的参数做clone操作,那么就必须使用Hashtable作为参数了,因为它还实现了Cloneable接口。

 

可以说这种时候,就是一个充分的理由,使用类(Hashtable)来声明了吗??

Java 编程中,以下场景优先选择使用接口而非抽象: - **需要多重继承**:接口允许一个实现多个接口,实现多重继承。如果一个需要具备多种能力,使用接口能更好地满足需求。例如,一个既需要具备飞行能力,又需要具备游泳能力,可以分别定义 `Flyable` 和 `Swimmable` 接口,让该同时实现这两个接口[^2][^3]。 ```java interface Flyable { void fly(); } interface Swimmable { void swim(); } class Duck implements Flyable, Swimmable { @Override public void fly() { System.out.println("Duck is flying"); } @Override public void swim() { System.out.println("Duck is swimming"); } } ``` - **定义一组规范**:接口定义规范和契约的最佳选择,它强制实现必须遵循接口定义。当需要为一组定义共同的行为规范,但这些之间没有明显的继承关系时,使用接口更合适。例如,定义一个 `Serializable` 接口,用于标记可以被序列化[^2]。 ```java interface Serializable { // 接口中可以不定义任何方法,仅作为一种标记 } class Person implements Serializable { // 的具体实现 } ``` - **降低耦合度**:接口更加灵活,能够降低之间的耦合度。通过接口,一个只需要关注接口定义的行为,而不需要关心具体的实现。例如,在依赖注入中,使用接口可以方便地替换具体的实现,提高代码的可维护性和可扩展性[^2]。 ```java interface Database { void connect(); } class MySQLDatabase implements Database { @Override public void connect() { System.out.println("Connected to MySQL database"); } } class PostgreSQLDatabase implements Database { @Override public void connect() { System.out.println("Connected to PostgreSQL database"); } } class Application { private Database database; public Application(Database database) { this.database = database; } public void run() { database.connect(); } } ``` - **考虑未来扩展**:接口的扩展性更好,可以在不影响现有实现的情况下,向接口中添加新的默认方法。当需要考虑未来可能的功能扩展时,优先使用接口。例如,在 Java 8 中,为 `List` 接口添加了 `forEach` 等默认方法,而不会影响现有的 `List` 实现[^2]。 ```java interface NewFeatureInterface { void oldMethod(); default void newMethod() { System.out.println("This is a new default method"); } } class NewFeatureImplementation implements NewFeatureInterface { @Override public void oldMethod() { System.out.println("Implementing old method"); } } ``` - **定义混合型**:接口适合定义混合型,一个可以通过实现多个接口来组合不同的功能。例如,一个可以同时实现 `Comparable` 和 `Cloneable` 接口,使其既可以进行比较,又可以进行克隆[^4]。 ```java class MyClass implements Comparable<MyClass>, Cloneable { private int value; public MyClass(int value) { this.value = value; } @Override public int compareTo(MyClass other) { return Integer.compare(this.value, other.value); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` - **构建非层次化型框架**:接口可构建非层次化型框架,避免层次结构的膨胀。当系统中的型关系比较复杂,不适合用单一的继承体系来表示时,使用接口可以更灵活地组织型[^4]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值