文章目錄
- 前言
- 一、什么是面向抽象編程?
- 二、傳統場景的類設計
- 2.1、項目場景設計
- 2.2、傳統類設計存在的問題
- 三、采用面向抽象編程的類設計
- 3.1、設計一個抽象類/接口
- 3.2、采用上轉型對象/接口回調調用子類方法
- 3.3、重新設計子類/被實現類
- 3.4、面向抽象編程的具體實現
- 四、面向抽象編程的優勢
- 總結
前言
面向抽象原則是面向對象四大基本原則的第一條,其重要性不言而喻,面向抽象原則分為抽象類、接口以及面向抽象編程,在之前的內容中我們詳細介紹了抽象類與接口,并對二者進行了對比,在本文中我們將詳細介紹什么是面向抽象編程,它與傳統編程相比有什么優勢?在開發中又該如何切實應用。一、什么是面向抽象編程?
面向抽象編程就是在設計一個類時,不讓該類面向具體的類,而是面向抽象類或接口,即所設計的類中的重要數據是抽象類或接口聲明的變量,而不是具體類聲明的變量。
下面我們將在具體的案例中進一步分析傳統類設計與面向抽象編程的類設計的區別。
二、傳統場景的類設計
在探討面向抽象編程之前,先看一下我們常規對于一個類的設計是什么樣的。
2.1、項目場景設計
項目場景:現在我們需要求一個圓柱體的體積,需要創建兩個類,圓類 Circle 和圓柱體類 Pillar。
首先我們創建一個 Circle 類,該類創建的對象 circle 調用 getArea() 方法可以計算出圓的面積,Circle 類的代碼如下:
package com.bailu.principle;public class Circle {final double PI = 3.14159;// 定義一個常量double r;/** 定義一個無參構造*/Circle() {}Circle(double r) {this.r = r;}public double getArea() {return (PI * r * r);}
}
接著我們再設計一個圓柱類 Pillar,該類創建的對象 pillar 調用 getVolume() 方法可以計算圓柱體的體積,Pillar 類的代碼如下:
package com.bailu.principle;public class Pillar {Circle bottom;// 將Circle類聲明的對象作為成員,圓柱體的底double height;/** 定義一個無參構造*/Pillar() {}Pillar(Circle bottom, double height) {this.bottom = bottom;this.height = height;}public double getVolume() {return bottom.getArea() * height;}
}
2.2、傳統類設計存在的問題
在上面的圓柱體類 Pillar 中,bottom 是用具體類 Circle 聲明的變量,如果在實際開發中不涉及用戶需要的變化,這樣設計并沒有什么不妥,但是某些時候,如果用戶希望將圓柱體改為三菱柱。顯然 Pillar 類是無法滿足的,并不能滿足用戶的需求。
那我們就需要對 Pillar 類進行修改。對于需要我們需要明確,柱體計算體積關鍵點在于計算底面積。我們不應該關心它的底具體是什么樣的形狀,而應該關心是否有計算面積的方法。
即我們在設計類的時候不應該將柱體的底看做某個具體類聲明的變量,我們上面這樣做,Pillar 類太過于依賴具體類,缺乏彈性,難以應對需求的變化。
三、采用面向抽象編程的類設計
3.1、設計一個抽象類/接口
如果我們采用面向抽象編程重新進行設計,首先需要設計一個抽象類用來獲取柱體底面積,該抽象類(或接口)我們定義為 Geometry(),我們在其中定義一個 getArea() 的抽象方法,具體代碼如下:
package com.bailu.principle;public abstract class Geometry {// 如果使用的是接口,用interface定義即可public abstract double getArea();
}
現在我們就可以面向 Geometry 類進行編碼,即通過上轉型對象/接口回調的方式,調用 Geometry 子類重寫的 getArea() 方法,這樣 Pillar 類就可以將計算柱體底面積的任務指派給 Geometry 子類的實例。
3.2、采用上轉型對象/接口回調調用子類方法
現在我們重新設計 Pillar 類不再依賴具體類,而是面向我們創建的抽象類/接口 Geometry,即 bottom 不再是具體類 Circle 聲明的變量,重新設計后 Pillar 類代碼如下:
package com.bailu.principle;public class Pillar {Geometry bottom;// bottom是抽象類Geometry聲明的變量double height;/** 定義一個無參構造*/Pillar() {}Pillar(Geometry bottom, double height) {this.bottom = bottom;this.height = height;}public double getVolume() {return bottom.getArea() * height;// bottom可以調用子類重寫的getArea()方法}
}
3.3、重新設計子類/被實現類
在采用面向抽象編程之后,我們就可以根據客戶需求對柱體要求的不同底進行設計。如圓形底和矩形底,我們創建抽象類 Geometry 的子類 Circle 和 Rectangle,重寫 Geometry 類的抽象方法 getArea()計算各自面積。
Circle 類對應代碼如下:
package com.bailu.principle;/** 當柱體的底為圓時*/
public class Circle extends Geometry {final double PI = 3.14159;// 定義一個常量double r;/** 定義一個無參構造*/Circle() {}Circle(double r) {this.r = r;}@Overridepublic double getArea() {return (PI * r * r);}
}
Rectangle 類對應代碼如下:
package com.bailu.principle;/** 當柱體的底為矩形時*/
public class Rectangle extends Geometry {double a, b;// 定義矩形的長寬/** 創建一個無參構造*/Rectangle() {}Rectangle(double a, double b) {this.a = a;this.b = b;}@Overridepublic double getArea() {return a * b;}
}
3.4、面向抽象編程的具體實現
現在我們就可以使用 Pillar 類創建出不同形狀底的柱體了,實現代碼如下:
package com.bailu.principle;public class ApplicationPillar {public static void main(String[] args) {Pillar pillar;Geometry bottom;bottom = new Rectangle(2, 3);// 抽象類的實例作為Rectangle類的上轉型對象pillar = new Pillar(bottom, 3);System.out.println("矩形底柱體體積為: " + pillar.getVolume());bottom = new Circle(2);// 抽象類的實例作為Circle類的上轉型對象pillar = new Pillar(bottom,2);System.out.println("圓底柱體體積為: " + pillar.getVolume());}
}
運行結果具體如下圖所示:
四、面向抽象編程的優勢
通過上面的案例我們可以發現,采用面向編程來設計 Pillar 類,使得 Pillar 類不再依賴于具體的某個類(Circle 類、Rectangle 類),當我們有新的需求增加時,我們只需要增加 Geometry 的子類即可,如增加一個三角形底的子類 Triangle,并不需要修改 Pillar 類的任何代碼就可以創建出三角形底的柱體。
總結
在本文給大家介紹了什么是面向抽象編程,并通過與傳統類設計的對比使大家明確面向抽象編程的優勢,設計一個類時,不讓該類面向具體的類,而是面向抽象類或接口,即所設計的類中的重要數據是抽象類或接口聲明的變量,而不是具體類聲明的變量,這樣就算需求發生變化,我們只需要增加或修改抽象類子類內容即可,而無需修改其他代碼。我是白鹿,一個不懈奮斗的程序猿。望本文能對你有所裨益,歡迎大家的一鍵三連!若有其他問題、建議或者補充可以留言在文章下方,感謝大家的支持!