1. 程式人生 > >再探Java抽象類與介面的設計理念差異

再探Java抽象類與介面的設計理念差異

Java抽象類與介面都可以實現功能與實現的分離,都對多型提供了很好的支援,那麼我們什麼時候應該使用抽象類或介面呢?在以前的一篇文章初探Java抽象類與介面中談到了他們語法的區別,在部落格通過模板方法模式深入理解Java抽象類中寫到了該如何正確使用抽象類,那麼這次我就從更高的層次上——設計思想 上談談它們的差異!

1、抽象類與介面的抽象層次是不同的
抽象類是對類抽象,介面是對行為抽象。類包含了屬性與行為,所以說介面是更具體的抽象。

2、抽象類與介面的設計層次是不同的
抽象類是一種自下而上的設計,先有子類才能提取公同的屬性與行為,抽象出父類;
介面是一種自上而下的設計,先規定行為方法,只要可以實現這些行為,就可以成為介面的實現類。

3、抽象類與其派生類的關係和介面與其實現類的關係本質是不同的
抽象類與其派生類是一種“is-a”關係,即父類和派生子類在概念上的本質是相同的(父子關係,血緣聯絡,很親密)。
介面與其實現類是一種“like-a”關係,即介面與實現類的關係只是實現了定義的行為,並無本質上的聯絡(契約關係,很淡漠的利益關係)。

舉個例子:比如說一個動物抽象類,定義了跑的方法、叫的方法,但如果一個汽車類可以實現跑、可以實現叫,它就可以繼承動物抽象類嗎?!這太不合理了,汽車不是動物呀!而如果通過介面定義跑的方法、叫的方法,汽車類作為實現類實現跑和叫,完全OK很合理,就因為沒有繼承關係的約束。

為了更好的闡述他們之間的區別,下面將使用一個很棒的例子來說明。該例子引自

博文連結

我們有一個Door的抽象概念,它具備兩個行為open()和close(),此時我們可以定義通過抽象類和介面來定義這個抽象概念:

抽象類:

abstract class Door{  
    abstract void open();  
    abstract void close();  
}  

介面:

interface Door{  
    void open();  
    void close();  
}  

至於其他的派生類可以通過:
1、使用extends使用抽象類方式定義Door
2、使用implements介面方式定義Door

這裡發現兩者並沒有什麼很大的差異,但是現在如果我們需要門具有報警的功能,那麼該如何實現呢?

解決方案一:給Door增加一個報警方法:alarm();

abstract class Door{  
    abstract void open();  
    abstract void close();  
    abstract void alarm();  
}  

或者

interface Door{  
    void open();  
    void close();  
    void alarm();  
}  

這種方法違反了面向物件設計中的一個核心原則 ISP (Interface Segregation Principle)—見批註,在Door的定義中把Door概念本身固有的行為方法和另外一個概念”報警器”的行為方法混在了一起。這樣引起的一個問題是那些僅僅依賴於Door這個概念的模組會因為”報警器”這個概念的改變而改變,反之依然。

解決方案二
既然open()、close()和alarm()屬於兩個不同的概念,那麼我們依據ISP原則將它們分開定義在兩個代表兩個不同概念的抽象類裡面,定義的方式有三種:
1、兩個都使用抽象類來定義。
2、兩個都使用介面來定義。
3、一個使用抽象類定義,一個是用介面定義。

由於java不支援多繼承所以第一種是不可行的。後面兩種都是可行的,但是選擇何種就反映了你對問題域本質的理解。

如果選擇第二種都是介面來定義,那麼就反映了兩個問題:
1、我們可能沒有理解清楚問題域,AlarmDoor在概念本質上到底是門還報警器。
2、如果我們對問題域的理解沒有問題,比如我們在分析時確定了AlarmDoor在本質上概念是一致的,那麼我們在設計時就沒有正確的反映出我們的設計意圖。因為你使用了兩個介面來進行定義,他們概念的定義並不能夠反映上述含義。

第三種,如果我們對問題域的理解是這樣的:AlarmDoor本質上Door,但同時它也擁有報警的行為功能,這個時候我們使用第三種方案恰好可以闡述我們的設計意圖。AlarmDoor本質是們,所以對於這個概念我們使用抽象類來定義,同時AlarmDoor具備報警功能,說明它能夠完成報警概念中定義的行為功能,所以alarm可以使用介面來進行定義。如下:

abstract class Door{  
    abstract void open();  
    abstract void close();  
}  

interface Alarm{  
    void alarm();  
}  

class AlarmDoor extends Door implements Alarm{  
    void open(){}  
    void close(){}  
    void alarm(){}  
}  

這種實現方式基本上能夠明確的反映出我們對於問題領域的理解,正確的揭示我們的設計意圖。其實抽象類表示的是”is-a”關係,介面表示的是”like-a”關係,大家在選擇時可以作為一個依據,當然這是建立在對問題領域的理解上的,比如:如果我們認為AlarmDoor在概念本質上是報警器,同時又具有Door的功能,那麼上述的定義方式就要反過來了。

批註: ISP(Interface Segregation Principle):面向物件的一個核心原則。它表明使用多個專門的介面比使用單一的總介面要好。
一個類對另外一個類的依賴性應當是建立在最小的介面上的。
一個介面代表一個角色,不應當將不同的角色都交給一個介面。沒有關係的介面合併在一起,形成一個臃腫的大介面,這是對角色和介面的汙染。

相關推薦

Java抽象介面設計理念差異

Java抽象類與介面都可以實現功能與實現的分離,都對多型提供了很好的支援,那麼我們什麼時候應該使用抽象類或介面呢?在以前的一篇文章初探Java抽象類與介面中談到了他們語法的區別,在部落格通過模板方法模式深入理解Java抽象類中寫到了該如何正確使用抽象類,那

Java抽象介面

寫了這麼久的介面,也很少用到抽象類。 在一些原始碼中又看到,自己平時基本不會用到抽象類,但是最近學習又不記得到底有什麼區別了,再來先看一下。 首先, java的面向物件的特徵是什麼: 面向物件程式設計有四個特徵:抽象,封裝,繼承,多型。 java墮胎的四種體現形式: 多型

Java抽象介面的區別及default關鍵字學習總結

抽象類 可看做是不可例項化的普通類,可以擁有構造方法,可以有main方法 抽象類中的方法可以是抽象方法(抽象方法必須存在於抽象類中),也可以是普通方法、靜態方法 可以宣告變數 抽象類可以繼承其它類,也可實現介面 抽象類的派生類,必須覆蓋父類中abstract修

Java抽象介面的區別

2014/07/16 | 分類: 基礎技術 | 6 條評論 | 標籤: 抽象類, 介面 分享到: 很多常見的面試題都會出諸如抽象類和介面有什麼區別,什麼情況下會使用抽象類和什麼情況你會使用介面這樣的問題。本文我們將仔細討論這些話題。 在討論它們之間的不同點之前,

java 抽象介面 note

抽象類(修飾符abstract) 兩種類:具體類和抽象類 抽象方法:設計目的就是讓子類來實現。子類繼承了抽象父類,如果沒有實現抽象父類,那麼子類還是一個抽象子類。否則子類一定要實現抽象父類裡的抽象方法,成為具體類。 如果一個方法被宣告為抽象類,則這個類必須宣告為抽象的。 在抽象類

JAVA抽象介面

Java抽象類 抽象方法:使用abstract關鍵字修飾的方法,沒有方法體,抽象方法只能使用public 或者protected修飾。 public abstract void fun(); 抽象

java 抽象介面的區別

抽象類:抽象類是用來捕捉子類的通用性的,不能被例項化,只能做為子類的超類,抽象類是被用來建立繼承層級裡子類的模板的。    首先了解一下抽象方法。抽象方法是一種特殊的方法,只宣告而沒有具體的實現,宣告格式為:abstract void fun (); 抽象方法必須由abs

JAVA抽象介面詳解 例子很好

在Java語言中, abstract class 和interface 是支援抽象類定義的兩種機制。正是由於這兩種機制的存在,才賦予了Java強大的 面向物件能力。abstract class和interface之間在對於抽象類定義的支援方面具有很大的相似性,甚至可以相互替

java基礎學習總結(十五):抽象介面

       抽象類與介面是java語言中對抽象概念進行定義的兩種機制,正是由於他們的存在才賦予java強大的面向物件的能力。他們兩者之間對抽象概念的支援有很大的相似,甚至可以互換,但是也有區別。  一、抽象類    &n

Java學習|抽象介面

對於面向物件程式設計,抽象是其一大特徵之一,在java中可以通過兩種形式來體現OOP的抽象:介面與抽象類 抽象類 抽象類為了繼承而存在,用abstract修飾,抽象類無法被例項化,定義了抽象類就是為了繼承他,並根據子類的實際需求來進行不同的實現,如果繼承一個抽象類,必須要實現父類的抽

Java抽象介面

程式設計中的抽象 表達一種概念而非實體 在一定程度上忽略細節而著眼大局(設計父類) 抽象類 使用關鍵字abstract修飾 抽象類的作用僅僅是表達介面,而不是具體的實現細節 抽象類無法制造出物件,但可以定義變數,存放非抽象子類的物件 抽

Java之路:抽象介面對比

先上圖: 下面詳細說下: 1、相同點 (1)都是抽象型別; (2)都可以有實現方法;抽象類中可以實現普通方法,介面中可以實現預設方法(Java 8)。 (3) 都可以不需要實現類或者繼承者去實現所有方法。(以前不行,現在介面中預設方法不需

java面向物件——抽象介面

1. 抽象類 抽象類就是指具有抽象方法並且使用abstract關鍵字修飾的類。 抽象類不能例項化物件,否則編譯出錯 抽象類中可以有成員變數,成員方法以及構造方法 抽象類中可以有抽象方法也可以沒有,但定義了抽象方法就必須是抽象類 抽象類的作用 抽象類的意義不在於

java學習筆記(七)--(抽象介面下)(介面的定義使用)

介面的定義與使用 介面優先原則:在一個操作即可以使用抽象類又可以使用介面的時候,優先考慮使用介面。 介面的定義(JDK8以前):介面就是抽象方法與全域性常量的集合(純粹版的抽象類),interfance關鍵字定義介面 interface IMessage{

“全棧2019”Java第六十六章:抽象介面詳細對比

難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 IntelliJ IDEA v2018.3 文章原文連結 “全棧2019”Java第六十六章:抽象類與介面詳細對比 下一章 “全棧2019”Java第六十七章:內部類、巢狀類

Java學習筆記之抽象介面的應用

1、抽象類的實際應用 — 定義模板 假設有這樣的場景,將人分為工人和學生,兩者都能說話,只是說話的內容不一樣,換句話說,說話這個功能應該是一個具體功能,說話的內容由學生和工人決定,我們可以用抽象類實現這個場景 abstract class Person2{ private S

java抽象介面小結

一、抽象類 抽象類的定義與使用 定義: 抽象類只是在普通類的基礎上擴充了一些抽象方法而已,所謂的抽象方法指的是隻宣告而未實現的方法(即沒有方 法體)。所有抽象方法要求使用abstract關鍵字來定義,並且抽象方法所在的類也一定要使用abstract關鍵字來 定義,表示抽象類。 定義一