所謂面向抽象編程是指當設計某種重要的類時,不讓該類面向具體的類,而是面向抽象類,及所設計類中的重要數據是抽象類聲明的對象,而不是具體類聲明的對象。就是利用abstract來設計實現用戶需求。
比如:我們有一個Circle圓類,計算其面積。
1
2
3
4
5
6
7
8
9
|
public
class
Circle
extends
Geometry{
double
r;
Circle(
double
r){
this
.r = r;
}
public
double
getArea(){
return
(
3.14
*r*r);
}
}
|
現在要設計一個Pillar(柱類),getvolume()可以計算柱體的體積。
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Pillar{
Circle bottom;
double
height;
Pillar(Circle bottom,
double
height){
this
.bottom = bottom;
this
.height = height;
}
public
double
getVolume(){
return
bottom.getArea() * height;
}
}
|
在Pillar(柱類)中,bottom是用具體類Circle聲明的對象,如果不涉及用戶需求的變化,上面Pillar(柱類)的設計沒有什么不妥,但是在某個時候,用戶希望Pillar(柱類)能創建出底部是三角形的柱體。顯然上面的Pillar(柱類)就無法創建出這樣的柱體,即上述設計的Pillar(柱類)不能應對用戶的這中需求。
重新修改Pillar(柱類)。注意到柱體的計算體積的關鍵是計算出底面積,一個柱體在計算底面積是不應該關心他的底是社么形狀的具體圖案,應該只關心這種圖像是否具有計算出面積的方法。因此,在設計Pillar(柱類)的時候不應當讓他的底是某個具體類的聲明的對象,一旦這么做,Pillar(柱類)就會依賴具體類,缺乏彈性,難以應對需求的變化。
第一步:定義一個抽象類Geometry,類中定義一個抽象的getArea()方法,Geometry類如下。這個抽象類將所有計算面積的方法都抽象為一個標識:getArea()無需考慮算法細節。
1
2
3
|
public
abstract
class
Geometry{
public
abstract
double
getArea();
}
|
第二步:Pillar(柱類)可以面向Geometry類編寫代碼,即Pillar(柱類)應當把Geometry類作為自己的成員,該成員可以調用Geometry的子類重寫的getArea()方法。這樣,Pillar(柱類)就將計算底面積的任務指派個Geometry類的子類的實例,不再依賴於某一個具體的類,而是面向Geometry類的,即Pillar(柱類)的bottom是用抽象類Geometry聲明的對象,而不是具體的某一類,新的Pillar(柱類)如下:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Pillar{
Geometry botom;
double
height;
Pillar(Geometry bottom,
double
height){
this
.bottom = bottom;
this
.height = height;
}
public
double
getVolume(){
return
bottom.getArea() * height;
}
}
|
在新增Geometry的子類時就不需要修改Pillar(柱類)的任何代碼,只需要增加一個Triangle類(三角形)。
1
2
3
4
5
6
7
8
9
10
|
public
class
Rectangle
extends
Geometry{
double
a,b;
Circle(
double
a,
double
b){
this
.a = a;
this
.b = b;
}
public
double
getArea(){
return
(a*b);
}
}
|
應用:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
class
Application{
public
state
void
main(String args[]){
Pillar pillar;
Geometry bottom;
bottom =
new
Circle(
10
);
//子類的上轉型對象
pillar =
new
Pillar(bottom,
10
);
System.out.println(
"圓柱體的體積"
+ pillar.getVolume());
bottom =
new
Rectangle(
10
,
10
);
pillar =
new
Pillar(bottom,
10
);
System.out.println(
"矩形底的體積"
+ pillar.getVolume());
}
}
|
總結:面向抽象編程目的是為了應對用戶需求的變化,將某個類中經常因需求變化而需要改變的代碼從類中分離出去。其核心是讓類中每種可能的變化對應的交給抽象類的一個子類去負責,從而讓該類的設計者不去關心具體的實現,避免所設計的類依賴於具體的實現。
關於抽象類:對於抽象類不能用new創建該類的對象,但可以成為其子類的上轉型對象,從而該對象可以調用子類重寫的方法。
一個非抽象類是某個抽象類的子類,那么它必須重寫父類的抽象方法,給出方法體。