原文:http://blog.csdn.net/sunboard/article/details/3831823java
1.概述
一個軟件設計的好壞,我想很大程度上取決於它的總體架構,而這個總體架構其實就是你對整個宏觀商業業務的抽象框架,當表明業務邏輯的高層抽象層結構 合理時,你底層的具體實現須要考慮的就僅僅是一些算法和一些具體的業務實現了。當你須要再開發另外一個相近的項目時,你之前的抽象層說不定還能夠再次利用 。面對對象的設計,複用的重點其實應該是抽象層的複用,而不是具體某一個代碼塊的複用。web
說到了抽象,我就不能不提到曾讓我頭痛的Java接口和Java抽象類了,這也是本文我想說的重點。算法
既然面向對象設計的重點在於抽象,那Java接口和Java抽象類就有它存在的必然性了。spring
Java接口(interface)和Java抽象類(abstract class)表明的就是抽象類型,就是咱們須要提出的抽象層的具體表現。OOP面向對象的編程,若是要提升程序的複用率,增長程序 的可維護性,可擴展性,就必須是面向接口的編程,面向抽象的編程,正確地使用接口、抽象類這些有用的抽象類型做爲你結構層次上的頂層。apache
Java接口和Java抽象類有太多類似的地方,又有太多特別的地方,究竟在什麼地方,纔是它們的最佳位置呢?把它們比較一下,你就能夠發現了。編程
- Java接口和Java抽象類最大的一個區別,就在於Java抽象類能夠提供某些方法的部分實現,而Java接口不能夠(就是interface中只能定義方法,而不能有方法的實現,而在abstract class中則能夠既有方法的具體實現,又有沒有具體實現的抽象方法),這大概就是Java抽象類惟一的優勢吧,但這個優勢很是有用。若是向一個抽象類里加入一個新的具體方法時,那麼它全部的子類都一會兒都獲得了這個新方法,而Java接口作不到這一點,若是向一個Java接口裏加入一個 新方法,全部實現這個接口的類就沒法成功經過編譯了,由於你必須讓每個類都再實現這個方法才行,這顯然是Java接口的缺點。這個在個人另一篇博客mapreduce 新舊API 區別中有提到相似的問題,在新的mapreduce api中更傾向於使用抽象類,而不是接口,由於這更容易擴展。緣由就是上面劃線部分所說的。
- 一個抽象類的實現只能由這個抽象類的子類給出,也就是說,這個實現處在抽象類所定義出的繼承的等級結構中,而因爲Java語言的單繼承性,因此抽象類做爲類型定義工具的效能大打折扣。在這一點上,Java接口的優點就出來了,任何一個實現了一個Java接口所規定的方法的類均可以具備這個接口的類型,而一個類能夠實現任意多個Java接口,從而這個類就有了多種類型。(使用抽象類,那麼繼承這個抽象類的子類類型就比較單一,由於子類只能單繼承抽象類;而子類可以同時實現多個接口,由於類型就比較多。接口和抽象類均可以定義對象,可是隻能用他們的具體實現類來進行實例化。)
- 從第2點不難看出,Java接口是定義混合類型的理想工具,混合類代表一個類不只僅具備某個主類型的行爲,並且具備其餘的次要行爲。
- 結合一、2點中抽象類和Java接口的各自優點,具精典的設計模式就出來了:聲明類型的工做仍然由Java接口承擔,可是同時給出一個Java 抽象類,且實現了這個接口,而其餘同屬於這個抽象類型的具體類能夠選擇實現這個Java接口,也能夠選擇繼承這個抽象類,也就是說在層次結構中,Java 接口在最上面,而後緊跟着抽象類,這下兩個的最大優勢都能發揮到極至了。這個模式就是「缺省適配模式」。在Java語言API中用了這種模式,並且全都遵循必定的命名規範:Abstract +接口名。(A extends AbstractB implements interfaceC,那麼A便可以選擇實現(@Override)接口interfaceC中的方法,也能夠選擇不實現;A便可以選擇實現(@Override)抽象類AbstractB中的方法,也能夠選擇不實現)
Java接口和Java抽象類的存在就是爲了用於具體類的實現和繼承的,若是你準備寫一個具體類去繼承另外一個具體類的話,那你的設計就有很大問題了。Java抽象類就是爲了繼承而存在的,它的抽象方法就是爲了強制子類必須去實現的。設計模式
使用Java接口和抽象Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。而不要用具體Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。api
2.實例
下面給出一個具體的接口Action,代碼以下所示:架構
- package org.springframework.webflow.execution;
- public interface Action {
- public Event execute(RequestContext context) throws Exception;
- }
在這個接口中,定義了一個沒有具體實現的方法,方法名叫作execute(),返回類型是Event。如前面第一條所述,接口中的方法都是沒有實現的。這些方法的具體實現是在實現(implements)這個接口的類中給出的。框架
再來看一個實現Action接口的抽象類AbstractAction,代碼以下。
- package org.springframework.webflow.action;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.beans.factory.BeanInitializationException;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.util.ClassUtils;
- import org.springframework.webflow.core.collection.AttributeMap;
- import org.springframework.webflow.execution.Action;
- import org.springframework.webflow.execution.Event;
- import org.springframework.webflow.execution.RequestContext;
-
- public abstract class AbstractAction implements Action, InitializingBean {
-
- protected final Log logger = LogFactory.getLog(getClass());
-
- public EventFactorySupport getEventFactorySupport() {
- return new EventFactorySupport();
- }
-
- public void afterPropertiesSet() throws Exception {
- try {
- initAction();
- } catch (Exception ex) {
- throw new BeanInitializationException("Initialization of this Action failed: " + ex.getMessage(), ex);
- }
- }
-
- protected void initAction() throws Exception {
- }
-
- protected Event success() {
- return getEventFactorySupport().success(this);
- }
-
- protected Event success(Object result) {
- return getEventFactorySupport().success(this, result);
- }
-
- protected Event error() {
- return getEventFactorySupport().error(this);
- }
-
- protected Event error(Exception e) {
- return getEventFactorySupport().error(this, e);
- }
-
- protected Event yes() {
- return getEventFactorySupport().yes(this);
- }
-
- protected Event no() {
- return getEventFactorySupport().no(this);
- }
-
- protected Event result(boolean booleanResult) {
- return getEventFactorySupport().event(this, booleanResult);
- }
-
- protected Event result(String eventId) {
- return getEventFactorySupport().event(this, eventId);
- }
-
- protected Event result(String eventId, AttributeMap resultAttributes) {
- return getEventFactorySupport().event(this, eventId, resultAttributes);
- }
-
- protected Event result(String eventId, String resultAttributeName, Object resultAttributeValue) {
- return getEventFactorySupport().event(this, eventId, resultAttributeName, resultAttributeValue);
- }
-
- public final Event execute(RequestContext context) throws Exception {
- Event result = doPreExecute(context);
- if (result == null) {
- result = doExecute(context);
- doPostExecute(context);
- } else {
- if (logger.isInfoEnabled()) {
- logger.info("Action execution disallowed; pre-execution result is '" + result.getId() + "'");
- }
- }
- return result;
- }
-
- protected String getActionNameForLogging() {
- return ClassUtils.getShortName(getClass());
- }
-
- protected Event doPreExecute(RequestContext context) throws Exception {
- return null;
- }
-
-
- protected abstract Event doExecute(RequestContext context) throws Exception;
-
- protected void doPostExecute(RequestContext context) throws Exception {
- }
- }
在抽象類AbstractAction中,既有具體實現的方法,又有沒有具體實現的抽象方法
- protected abstract Event doExecute(RequestContext context) throws Exception;
須要注意的是在抽象類中,若是方法沒有具體實現(就是方法後面沒有{}),那麼必須加上abstract來聲明這個方法,而接口中不須要使用abstract來聲明(抽象類之因此被稱爲抽象類,就是由於它包含有抽象方法。含有抽象方法的類叫作抽象類)。
------------------------------------------------------------------------------------------------------------------------------------------------
含有abstract修飾符的class 即爲抽象類,abstract類不能建立實例對象,含有abstract的方法的類必須定義爲abstract class ,abstract class 裏的方法沒必要是抽象的,抽象來中定義抽象方法必須放在具體子類中實現,因此呀,不能有抽象的構造方法或抽象的靜態方法,若是子類沒有實現抽象父類中的全部方法,那麼,子類也必須定義爲抽象類。
接口(interface)能夠說成是抽象類的特例。接口中的全部方法都必須是抽象的,接口中的方法定義默認爲public abstract 。接口中的變量是全局常量,即public static final修飾的。
看一下他們在語法上的區別吧!
1,抽象類裏能夠有構造方法,而接口內不能有構造方法。
2,抽象類中能夠有普通成員變量,而接口中不能有普通成員變量。
3,抽象類中能夠包含非抽象的普通方法,而接口中全部的方法必須是抽象的,不能有非抽象的普通方法。
4,抽象類中的抽象方法的訪問類型能夠是public ,protected和默認類型,但接口中的抽象方法只能是public類型的,而且默認即爲public abstract類型。
5,抽象類中能夠包含靜態方法,接口內不能包含靜態方法。
6,抽象類和接口中均可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型能夠任意,但接口中定義的變量只能是public static類型,而且默認爲public static類型。
7,一個類能夠實現多個接口,但只能繼承一個抽象類。
再補充點二者在應用上的區別:
接口更多的是在系統框架設計方法發揮做用,主要定義模塊之間的通訊,而抽象類在代碼實現方面發揮做用,能夠實現代碼的重用