面向抽象編程和麵向介面編程

来源:https://www.cnblogs.com/chiweiming/archive/2018/07/07/9229457.html
-Advertisement-
Play Games

原創 以下內容來自《Java 2實用教程》,主編:耿祥義、張躍平 鑒於面向抽象編程和麵向介面編程思維培養的重要性,寫此博客鞏固。 面向抽象編程: 在設計程式時,經常會使用到abstract類,其原因是,abstract類只關心操作,而不關心這些操作具體的實現細節, 可以使程式的設計者把主要精力放在程 ...


原創


以下內容來自《Java 2實用教程》,主編:耿祥義、張躍平

鑒於面向抽象編程和麵向介面編程思維培養的重要性,寫此博客鞏固。

面向抽象編程:

  在設計程式時,經常會使用到abstract類,其原因是,abstract類只關心操作,而不關心這些操作具體的實現細節,

可以使程式的設計者把主要精力放在程式的設計上,而不必拘泥於細節的實現(將這些細節留給子類的設計者),即避免

設計者把大量的時間和精力花費在具體的演算法上。例如,在設計地圖時,首先考慮地圖最重要的輪廓,不必去考慮諸如城

市中的街道牌號等細節,細節應當由抽象類的非抽象子類去實現,這些子類可以給出具體的實例,來完成程式功能的具體

實現。在設計一個程式時,可以通過在abstract類中聲明若幹個abstract方法,表明這些方法在整個系統設計中的重要性,

方法體的內容細節由它的非abstract子類去完成。

  使用多態進行程式設計的核心技術之一是使用上轉型對象,即將abstract類聲明的對象作為其子類對象的上轉型對象,

那麼這個上轉型對象就可以調用子類重寫的方法。

  所謂面向抽象編程,是指當設計某種重要的類時,不讓該類面向具體的類,而是面向抽象類,即所設計類中的重要數據

是抽象類聲明的對象,而不是具體類的聲明的對象。

  以下通過一個簡單的問題來說明面向抽象編程的思想。

  例如,我們已經有了一個Circle類(圓類),該類創建的對象Circle調用getArea()方法可以計算圓的面積。Circle類

的代碼如下:

Circle.java

1 public class Circle {
2     double r;
3     Circle(double r){
4         this.r=r;
5     }
6     public double getArea() {
7         return(3.14*r*r);
8     }
9 }

   現在要設計一個Pillar類(柱類),該類的對象調用getVolume()方法可以計算柱體的體積。Pillar類的代碼如下:

Pillar.java

 1 public class Pillar {
 2     Circle bottom;    //bottom是用具體類Circle聲明的對象
 3     double height;
 4     Pillar (Circle bottom,double height){
 5         this.bottom=bottom;
 6         this.height=height;
 7     }
 8     public double getVolume() {
 9         return bottom.getArea()*height;
10     }
11 }

  上述Pillar類中,bottom是用具體類Circle聲明的對象,如果不涉及用戶需求的變化,上面Pillar類的設計沒有什麼不妥,

但是在某個時候,用戶希望Pillar類能創建出底是三角形的柱體。顯然上述Pillar類無法創建出這樣的柱體,即上述設計的Pillar

類不能應對用戶的這種需求(軟體設計面臨的最大問題是用戶需求的變化)。我們發現,用戶需求的柱體的底無論是何種圖形,但

有一點是相同的,即要求該圖形必須有計算面積的行為,因此可以用一個抽象類封裝這個行為標準:在抽象類里定義一個抽象方法

abstract double getArea(),即用抽象類封裝許多子類都必有的行為。

  現在我們來重新設計Pillar類。首先,我們註意到柱體計算體積的關鍵在計算出底面積,一個柱體在計算底面積時不應該關心

它的底是什麼形狀的具體圖形,只應該關心這種圖形是否具有計算面積的方法。因此,在設計Pillar類時不應該讓它的底是某個具體

類聲明的對象,一旦這樣做,Pillar類就依賴該具體類,缺乏彈性,難以應對需求的變化。

  下麵我們將面對抽象重新設計Pillar類。首先編寫一個抽象類Geometry,該抽象類中定義了一個抽象的getArea()方法。

Geometry類如下:

Geometry.java

1 public abstract class Geometry {
2     public abstract double getArea();
3 }

  上述抽象類將所有計算面積的演算法抽象為一個標識:getArea(),即抽象方法,不用考慮演算法的細節。

  現在Pillar類的設計者可以面向Geometry類編寫代碼,即Pillar類應該把Geometry對象作為自己的成員,該成員可以調用Geometry

的子類重寫的getArea()方法。這樣一來,Pillar類就可以將計算底面積的任務指派給Geometry類的子類的實例(用戶的各種需求將由

不同的子類去負責)。

  以下Pillar類的設計不再依賴具體類,而是面向Geometry類,即Pillar類中的bottom是用抽象類Geometry聲明的對象,而不是具體類

聲明的對象。重新設計的Pillar類的代碼如下:

Pillar.java

 1 public class Pillar {
 2     Geometry bottom;    //bottom是抽象類Geometry聲明的變數
 3     double height;
 4     Pillar (Geometry bottom,double height){
 5         this.bottom=bottom;
 6         this.height=height;
 7     }
 8     public double getVolume() {
 9         if(bottom==null) {
10             System.out.println("沒有底,無法計算體積");
11             return -1;
12         }
13         return bottom.getArea()*height;    //bottom可以調用子類重寫的getArea方法
14     }
15 }

  下列Circle和Rectangle類都是Geometry的子類,二者都必須重寫Geometry類和getArea()方法來計算各自的面積。

Circle.java

1 public class Circle extends Geometry{
2     double r;
3     Circle(double r){
4         this.r=r;
5     }
6     public double getArea() {
7         return(3.14*r*r);
8     }
9 }

Rectangle.java

 1 public class Rectangle {
 2     double a,b;
 3     Rectangle(double a,double b){
 4         this.a=a;
 5         this.b=b;
 6     }
 7     public double getArea() {
 8         return a*b;
 9     }
10 }

  註意到,當增加了Circle和Recangle類後,我們不必修改Pillar類的代碼。現在,我們就可以用Pillar類創建

出具有矩形底或圓形底的柱體了,如下列Application.java所示,程式運行效果如圖5.13所示。

Application.java

 1 public class Application {
 2     public static void main(String args[]) {
 3         Pillar pillar;
 4         Geometry bottom=null;
 5         pillar = new Pillar(bottom,100);    //null底的柱體
 6         System.out.println("體積"+pillar.getVolume());
 7         bottom=new Rectangle(12,22);
 8         pillar=new Pillar(bottom,58);    //pillar是具有矩形底的柱體
 9         System.out.println("體積"+pillar.getVolume());
10         bottom=new Circle(10);
11         pillar =new Pillar (bottom,58);    //pillar是具有圓形底的柱體
12         System.out.println("體積"+pillar.getVolume());
13     }
14 }

  通過面向抽象類設計Pillar類,使得該Pillar類不再依賴具體類,因此每當系統增加新的Geometry的子類時,

例如增加一個Triangele子類,那麼我們不需要修改Pillar類的任何代碼,就可以使用Pillar創建出具有三角形底

的柱體。

  通過前面的討論我們可以做出如下總結:

  面向抽象編程的目的是為了應對用戶需求的變化,將某個類中經常因需求變化而需要改變的代碼從該類中分離

出去。面向抽象編程的核心是讓類中每種可能的變化對應地交給抽象類的一個子類去負責,從而讓該類的設計者不

去關心具體實現,避免所設計的類依賴於具體的實現。面向抽象編程使設計的類容易應對用戶需求的變化。

面向介面編程:

  抽象類最本質的特性是可以包含抽象方法,這一點和介面類似,只不過介面中只有抽象方法而已。抽象類將其抽象方法

的實現交給其子類,而介面將其抽象方法的實現交給實現該介面的類。在設計程式時,學習怎樣面向介面去設計程式。介面

只關心操作,但不關心這些操作的具體實現細節,可以使我們把主要精力放在程式的設計上,而不必拘泥於細節的實現。也

就是說,可以通過在介面中聲明若幹個abstract方法,表明這些方法的重要性,方法體的內容細節由實現介面的類去完成。

使用介面進行程式設計的核心思想是使用介面回調,即介面變數存放實現該介面的類的對象的引用,從而介面變數就可以回

調類實現的介面方法。利用介面也可以體現程式設計的“開-閉原則”,即對擴展開放,對修改關閉。例如,程式的主要設計

者可以設計出如下圖所示的一種結構關係。

  從下圖可以看出,當程式再增加實現介面的類(由其他設計者去實現),介面變數variable所在的類不需要做任何修改,

就可以回調類重寫的介面方法。

  

  當然,在程式設計好後,首先應當對介面的修改“關閉”,否則,一旦修改介面,例如,為它增加一個abstract方法,

那麼實現該介面的類都需要作出修改。但是,程式設計好後,應當對增加實現介面的類“開放”,即在程式中再增加實現

介面的類時,不需要修改其他重要的類。

  個人的一點小薄見:

  面向抽象編程和麵向介面編程的思路都是一樣的,面向抽象編程依靠上轉型對象來實現;面向介面編程依靠介面回調

來實現;這種思想對於軟體設計十分重要。Java中的一大法寶是多態,多態分兩種,其中一種就是通過繼承來實現的,子

類通過定義自己的行為來“展示自己”,每個子類都有不同的行為,所以展現出多態性。而我們可以建立一個類,這個類

可以幫助“每一個子類”來展現他們自己,而不用他們自己親自動手,這會大大縮減程式的代碼長度,假如有100個子類,

如果要求每一個子類都親自展現自己,必須定義100段不同的代碼;而通過一個類輪流為它們服務,這會顯得更方便,這

楊的一個幫助子類展現自己的類被稱為面向抽象的類(介面也一樣),面向抽象的類為子類實例的上轉型對象,通過調用

子類重寫的方法來實現多態。

19:17:05

2018-07-07


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前面我們已經提到單個伺服器再優化,它的處理能力都是有上限的,因此我們選擇多擴容以及使用緩存和消息隊列等對程式進行優化。 下麵介紹另一種方法,隨著項目需求完成越來越多,應用自然也會越來越大,架構師將一個應用整體拆分成多個應用。 拆分的原則: 1.業務優先,確定業務邊界 2.循序漸進,邊拆分邊測試 3. ...
  • A.所屬包 java.lang B.聲明 public class Object C.概述 是所有類的父類 D.構造方法: Object() E.常用成員方法 a.protected Object clone() 創建並返回該對象的一個副本,需要實現Cloneable介面重寫此方法 b.public ...
  • Sublime下配置python編譯環境及新手使用指導: 1.編譯環境配置 1.點擊 "官方網址" 從 Sublime Text 3 官方獲取用於安裝的代碼。從菜單欄View Show Console或者使用Ctrl+`(esc鍵下麵的按鍵),調出sublime的控制台,將官網中的python代碼粘 ...
  • 遇到這樣一個問題。我想要統計某個文件夾下有多少個py文件怎麼辦。 用python能解決嗎?答案,能。 解決辦法,使用glob 代碼如下: 很簡單的幾行代碼,。 第一步,導入glob庫 第二步,使用glob下麵的glob的方法,參數是路徑下判斷的文件 第三步:列印: 結果: 這個是和我當前目錄所有的p ...
  • 消息隊列已經逐漸成為企業IT系統內部通信的核心手段。它具有低耦合、可靠投遞、廣播、流量控制、最終一致性等一系列功能,成為非同步RPC的主要手段之一。 消息被處理的過程相當於流程A被處理。我們這裡以一個實際的模型來討論下,比如用戶下單成功時給用戶發簡訊,如果沒有這個消息隊列,我們會選擇同步調用發簡訊的接 ...
  • 作為一個比較喜歡出去見識世界、看看自然風光的人,這幾年有幸跑了一些地方,在祖國大地不同的地方見識了不同的人文風物,手機里也存了不少照片,想著如果以某種方式展現來回憶我的旅途的話,或許會給自己帶來不一樣的體驗。目標口號已經想好:去過的風景,直觀豐富地展示你的人生旅途,帶來新的回憶感受。在看到leafl ...
  • 考慮一下利用Python製作一個整蠱、木馬軟體,我提供思路。(清楚到沒學過編程的人也理解) 1、首先一個黑客做一個整蠱或者木馬軟體,一定不會讓你能夠關閉它。 2、裡面經常會附帶欺騙的方法。 3、最終實現某種目的。 前段時間在抖音上看到個有趣的程式,看樣子是VB寫的,首先就要用到欺騙的方法,利用軟體名 ...
  • 單例模式是java的一種設計模式,它是指在設計一個類時需要保證在整個程式運行期間針對該類值存在一個實例對象。例: class Single{ private static Single INSTANCE = new Single(); private Single() {} public stati ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...