所谓面向抽象编程是指当设计某种重要的类时,不让该类面向具体的类,而是面向抽象类,及所设计类中的重要数据是抽象类声明的对象,而不是具体类声明的对象。就是利用abstract来设计实现用户需求。
比如:我们有一个Circle圆类,计算其面积。
public class Circle extends Geometry{
double r;
Circle( double r){
this .r = r;
}
public double getArea(){
return ( 3.14 *r*r);
}
}
现在要设计一个Pillar(柱类),getvolume()可以计算柱体的体积。
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()无需考虑算法细节。
public abstract class Geometry{
public abstract double getArea();
}
第二步:Pillar(柱类)可以面向Geometry类编写代码,即Pillar(柱类)应当把Geometry类作为自己的成员,该成员可以调用Geometry的子类重写的getArea()方法。这样,Pillar(柱类)就将计算底面积的任务指派个Geometry类的子类的实例,不再依赖于某一个具体的类,而是面向Geometry类的,即Pillar(柱类)的bottom是用抽象类Geometry声明的对象,而不是具体的某一类,新的Pillar(柱类)如下:
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类(三角形)。
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);
}
}
应用:
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创建该类的对象,但可以成为其子类的上转型对象,从而该对象可以调用子类重写的方法。
一个非抽象类是某个抽象类的子类,那么它必须重写父类的抽象方法,给出方法体。