文章目录
- 前言
- 一、什么是面向抽象编程?
- 二、传统场景的类设计
- 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 类的任何代码就可以创建出三角形底的柱体。
总结
在本文给大家介绍了什么是面向抽象编程,并通过与传统类设计的对比使大家明确面向抽象编程的优势,设计一个类时,不让该类面向具体的类,而是面向抽象类或接口,即所设计的类中的重要数据是抽象类或接口声明的变量,而不是具体类声明的变量,这样就算需求发生变化,我们只需要增加或修改抽象类子类内容即可,而无需修改其他代码。我是白鹿,一个不懈奋斗的程序猿。望本文能对你有所裨益,欢迎大家的一键三连!若有其他问题、建议或者补充可以留言在文章下方,感谢大家的支持!