8.1 接口的概念和基本特征
(1)、接口中的成員變量默認都是public、static、final類型的,必須被顯式初始化;
(2)、接口中的方法默認都是public、abstract類型的;
(3)、接口中只能包含public、static、final類型的成員變量和public、abstract類型的成員方法;
(4)、接口沒有構造方法,不能被實例化;
(5)、一個接口不能實現另一個接口,但可以繼承多個其他接口;
(6)、接口必須通過類來實現它的抽象方法。類實現接口的關鍵字是implements;
(7)、與子類繼承抽象父類相似,當類實現了某個接口時,它必須實現接口中所有的抽象方法,否則這個類必須被定義為抽象類;
(8)、不允許創建接口類型的實例,但允許定義接口類型的引用變量,該變量引用實現了這個接口的類的實例;
(9)、一個類只能繼承一個直接的父類,但能實現多個接口。
8.2 比較抽象類與接口
相同點:
- 代表系統的抽象層
- 都不能被實例化
- 都能包含抽象方法
兩大區別:
- 在抽象類中可以為部分方法提供默認的實現,從而避免在子類中重復實現它們,提高代碼的可重用性,這是抽象類的優勢所在;而接口中只能包含抽象方法;
- 一個類只能繼承一個直接的父類,這個父類有可能是抽象類;但一個類可以實現多個接口,這是接口的優勢所在。
使用接口和抽象類的原則:
- 用接口作為系統與外界交互的窗口;
- 由于外界使用者依賴系統的接口,并且系統內部會實現接口,因此接口本身必須十分穩定,接口一旦制訂,就不允許隨意修改,否則會對外界使用者及系統內部都造成影響。
- 用抽象類來定制系統中的擴展點。
8.3 與接口相關的設計模式
8.3.1 定制服務模式
如何設計接口?定制服務模式提出了設計精粒度的接口的原則。
8.3.2 適配器模式
當兩個系統之間接口不匹配時,如果處理?適配器模式提供了接口轉換方案。
包括繼承實現方式和組合實現方式。優先考慮用組合關系來實現適配器。
8.3.3 默認適配器模式
為了簡化編程,JDK為MouseListener提供了一個默認適配器MouseAdapter,它實現了MouseListener接口,為所有的方法提供了空的方法體。用戶自定義的MyMouseLIstener監聽器可以繼承MouseAdapter類,在MyMouseListener類中,只需要覆蓋特定的方法,而不必實現所有的方法。使用默認適配器可以簡化編程,但缺點是該類不能在繼承其他的類。
8.3.4 代理模式
下面以房屋出租人的代理為例,介紹代理模式的運用。在下圖中,出租人Renter和代理Deputy都具有RenterIFC接口。Tenant類代表租賃人,HouseMarket類代表整個房產市場,它記錄了所有房產代理人的信息,出租人從房產市場找到房產代理人。

為了簡化起見,假定一個代理人只會為一個出租人做代理,租賃人租房屋rentHouse()的大致過程如下:
- 從房產市場上找到一個房產代理人,即調用HouseMarket對象的findRenter()方法;
- 報出期望的租金價格,征求代理人的意見,即調用Deputy對象的isAgree()方法;
- 代理人的處理方式為:如果租賃人的報價低于出租人的租金價格底線,就立即做出拒絕答復;否則征求出租人的意見,即調用Renter對象的isAgree()方法。
- 出租人的處理方式為:如果租賃人的報價比租金價格底線多100元,就同意出租
- 如果租賃人得到代理人同意的答復,就從存款中取出租金,通知代理人領取租金,即調用Deputy對象的fetchRent()方法
- 代理人通知出租人領取租金,即調用Renter對象的fecthRent()方法。

房屋租賃交易順利執行的時序圖
源代碼:
/**
* RetnerIFC 接口,它定義了出租人的兩個行為,即決定是否同意按租賃人提出的價格出租房屋,以及收房租
*
* @author XL
*
*/
public interface RenterIFC {
/**
* 是否同意按租賃人提出的價格出租房屋
*
* @param expectedRent
* @return
*/
public boolean isAgree(double expectedRent);
/**
* 收房租
*
* @param rent
*/
public void fetchRent(double rent);
}
/**
* 房屋出租人
*
* @author XL
*
*/
public class Renter implements RenterIFC {
/**
* 房屋租金最低價格
*/
private double rentDeadLine;
/**
* 存款
*/
private double money;
/**
* @param rentDeadLine
* @param money
*/
public Renter(double rentDeadLine, double money) {
super();
System.out.println("New Renter, rentDeadLine: " + rentDeadLine
+ ", saveMoney: " + money);
this.rentDeadLine = rentDeadLine;
this.money = money;
}
/*
* (non-Javadoc)
*
* @see chapter08.d0800.RenterIFC#fetchRent(double)
*/
public void fetchRent(double rent) {
System.out.println("OK, you can use the house.");
money += rent;
}
/*
* (non-Javadoc) 如果租賃人的期望價格比房屋租金最低價格多100元,則同意出租
*
* @see chapter08.d0800.RenterIFC#isAgree(double)
*/
public boolean isAgree(double expectedRent) {
System.out.println("If the money less 100 than the rentDeadLine.");
return expectedRent - this.rentDeadLine > 100;
}
/**
* @return
*/
public double getRentDeadLine() {
return rentDeadLine;
}
}
/**
* 房產代理人
*
* @author XL
*
*/
public class Deputy implements RenterIFC {
private Renter renter;
/**
* 接受代理
*
* @param renter
*/
public void registerRenter(Renter renter) {
System.out.println("OK, I have some business.");
this.renter = renter;
}
public void fetchRent(double rent) {
System.out.println("Get the monty: " + rent);
renter.fetchRent(rent);
}
/*
* (non-Javadoc) 如果租賃人的期望價格低于房屋租金最低價格,則不同意出租 否則請示出租人的意見
*
* @see chapter08.d0800.RenterIFC#isAgree(double)
*/
public boolean isAgree(double expectedRent) {
//
if (expectedRent < renter.getRentDeadLine()) {
System.out.println("Sorry, you can't rent the house.");
return false;
} else {
System.out.println("Let me ask the renter.");
return renter.isAgree(expectedRent);
}
}
}
import java.util.HashSet;
import java.util.Set;
/**
* @author XL
*
*/
public class HouseMarket {
private static Set<RenterIFC> renters = new HashSet<RenterIFC>();
public static void registerRenter(RenterIFC deputy) {
System.out.println("A new man has registered!");
renters.add(deputy);
}
public static RenterIFC findRenter() {
System.out.println("Let's find something!");
return (RenterIFC) renters.iterator().next();
}
}
/**
* 房屋租賃人
*
* @author XL
*
*/
public class Tenant {
private double money;
public Tenant(double money) {
//
System.out.println("New Tenant!");
System.out.println("I have " + money);
this.money = money;
}
public boolean rentHouse(double expectedRent) {
// 從房地產市場找到一個房產代理人
RenterIFC renter = HouseMarket.findRenter();
System.out.println("I can offer " + expectedRent);
// 如果代理人不同意預期的租金價格,就拉倒,否則繼續執行
if (!renter.isAgree(expectedRent)) {
System.out.println("I can't offer any more!");
return false;
}
// 從存款中取出預付租金
money -= expectedRent;
System.out.println("OK, get the money, " + expectedRent);
// 把租金交給房產代理人
renter.fetchRent(expectedRent);
return true;
}
}
/**
* @author XL
*
*/
public class AppMain {
/**
* @param args
*/
public static void main(String[] args) {
// 創建一個房屋出租人,房屋租金最低價格為2000元,存款1萬元
Renter renter = new Renter(2000, 10000);
// 創建一個房產代理人
Deputy deputy = new Deputy();
// 房產代理人到房產市場登記
HouseMarket.registerRenter(deputy);
// 建立房屋出租人和房產代理人的委托關系
deputy.registerRenter(renter);
// 創建一個房屋租賃人,存款為2萬元
Tenant tenant = new Tenant(20000);
// 房屋租賃人試圖租賃期望租金為1800元的房屋,遭到房產代理人拒絕
tenant.rentHouse(1800);
// 房屋租賃人試圖租賃期望租金為2300元的房屋,租房成功
tenant.rentHouse(2300);
}
}
輸出結果:
New Renter, rentDeadLine: 2000.0, saveMoney: 10000.0
A new man has registered!
OK, I have some business.
New Tenant!
I have 20000.0
Let's find something!
I can offer 1800.0
Sorry, you can't rent the house.
I can't offer any more!
Let's find something!
I can offer 2300.0
Let me ask the renter.
If the money less 100 than the rentDeadLine.
OK, get the money, 2300.0
Get the monty: 2300.0
OK, you can use the house.
8.3.5 標識類型模式
標識類型接口沒有任何方法,僅代表一種抽象類型。
在JDK中,有如下兩個典型的標識類型接口:
- java.io.Serializable接口:實現該接口的類可以被序列化。
- java.io.Remote接口:實現該接口的類的實例可以作為遠程對象。
8.3.6 常量接口模式
posted on 2008-02-19 18:03
CoderDream 閱讀(402)
評論(0) 編輯 收藏 所屬分類:
經驗點滴