一、抽象类和接口
当设计一个类时,不让该类面向具体的类,而是面向抽象类或接口,即所设计类中的重要数据是抽象类或接口声明的变量,而不是具体类声明的变量
代码示例:
抽象类:
public abstract class A {
public abstract int add(int x,int y);
}
public class B extends A {
public int add(int x,int y) {
return x+y;
}
}
public class Application {
public static void main(String args[]) {
A a;
a=new B(); //a是B类对象的上转型对象
int m=a.add(3,2); //a调用子类B重写的add()方法
System.out.println(m); //输出结果为5
}
}
接口:
public interface Com {
public abstract int sub(int x,int y);
}
class ComImp implements Com {
public int sub(int x,int y) {
return x-y;
}
}
public class Application {
public static void main(String args[]) {
Com com;
com=new ComImp(); //com变量存放ComImp类的对象的引用
int m=com.sub(8,2); //com回调ComImp类实现的接口方法
System.out.println(m); //输出结果为6
}
}
二、面向抽象?
代码示例:
abstract class A {
public abstract int add(int a, int b);
}
class B extends A{
public int add(int a, int b) {
return a*b;
}
}
public class TestClass {
public static void main(String[] args) {
A a = null; // 面向抽象原则(声明抽象类/接口对象)
a = new B(); // a是B类的上转型对象
int m = a.add(2,3);
System.out.println("m = "+m);
/* 等价于:
B b = new B();
int m = b.add(2, 3);
System.out.println("m = "+m);
*/
}
}
?我们已经有了一个Circle类,该类创建的对象circle调用getArea()方法可以计算圆的面积。
现在要设计一个Pillar类(柱类),该类的对象调用getVolume()方法可以计算柱体的体积,Pillar类的代码如下:
public class Pillar {
Circle bottom; //将Circle对象作为成员,bottom是用具体类声明的变量
double height;
Pillar (Circle bottom,double height) {
this.bottom=bottom;this.height=height;
}
public double getVolume() {
return bottom.getArea()*height;
}
}
如果不涉及用户需求的变化,上面Pillar类的设计没有什么不妥,但是在某个时候,用户希望Pillar类能创建出底是三角形的柱体。显然上述Pillar类无法创建出这样的柱体,即上述设计的Pillar类不能应对用户的这种需求。
?因此,我们在设计Pillar类时不应当让它的底是某个具体类声明的变量,一旦这样做,Pillar类就依赖该具体类,缺乏弹性,难以应对需求的变化。
下面我们将面向抽象重新设计Pillar类。首先编写一个抽象类Geometry(或接口),该抽象类(接口)中定义了一个抽象的getArea()方法,Geometry类如下:
public abstract class Geometry { //如果使用接口需用interface来定义Geometry。
public abstract double getArea();
}
?Pillar类的设计不再依赖具体类,而是面向Geometry类
public class Pillar {
Geometry bottom; //bottom是抽象类Geometry声明的变量
double height;
Pillar (Geometry bottom,double height) {
this.bottom = bottom; this.height=height;
}
public double getVolume() {
return bottom.getArea()*height;
}
}
Circle和Rectangle类都是Geometry的子类,二者都必须重写Geometry类的getArea()方法来计算各自的面积。
Circle类:
public class Circle extends Geometry {
double r;
Circle(double r) {
this.r=r;
}
public double getArea() {
return(3.14*r*r);
}
}
Rectangle类:
public class Rectangle extends Geometry {
double a,b;
Lader(double a,double b) {
this.a=a; this.b=b;
}
public double getArea() {
return a*b;
}
}
?现在就可以用Pillar 类创建出具有矩形底或圆形底的柱体:
public class Application{
public static void main(String args[]){
Pillar pillar;
Geometry bottom;
bottom=new Rectangle(12,22,100);
pillar = new Pillar (bottom,58); //pillar是具有矩形底的柱体
System.out.println("矩形底的柱体的体积"+pillar.getVolume());
bottom=new Circle(10);
pillar = new Pillar (bottom,58); //pillar是具有圆形底的柱体
System.out.println("圆形底的柱体的体积"+pillar.getVolume());
}
}
?Pillar类不再依赖具体类,因此每当系统增加新的Geometry的子类时,比如增加一个Triangle子类,那么不需要修改Pillar类的任何代码,就可以使用Pillar创建出具有三角形底的柱体。
完整代码:
public abstract class Geometry { //如果使用接口需用interface来定义Geometry。
public abstract double getArea();
}
public class Circle extends Geometry {
double r;
Circle(double r) {
this.r=r;
}
public double getArea() {
return(3.14*r*r);
}
}
public class Rectangle extends Geometry {
double a,b;
Rectangle(double a,double b) {
this.a=a; this.b=b;
}
public double getArea() {
return a*b;
}
}
public class Pillar {
Geometry bottom; //bottom是抽象类Geometry声明的变量
double height;
Pillar (Geometry bottom,double height) {
this.bottom=bottom; this.height=height;
}
public double getVolume() {
return bottom.getArea()*height; //bottom可以调用子类重写的getArea方法
}
}
public class Application{
public static void main(String args[]){
Pillar pillar;
Geometry bottom;
bottom=new Rectangle(12,22);
pillar =new Pillar (bottom,58); //pillar是具有矩形底的柱体
System.out.println("矩形底的柱体的体积"+pillar.getVolume());
bottom=new Circle(10);
pillar =new Pillar (bottom,58); //pillar是具有圆形底的柱体
System.out.println("圆形底的柱体的体积"+pillar.getVolume());
}
}
实例:?
编写一个手机拼装程序
请编写一个接口(或抽象类) Screen, 里面声明一个方法showScreen,返回值类型是String
编写三个类,都继承(实现上面的Screen) :
索尼Sony,实现它的showScreen方法,返回值是"索尼”
三星SAMSUNG,实现它的showScreen方法,返回值是"三星"
再编写一个接口Battery,里面声明一个方法showBattery,返回值类型是String
继承(实现) Battery,写两个类:
联想Lenovo,实现它的showBattery方法, 返回值是"联想"
诺基亚NOKIA ,实现它的showBattery方法,返回值是"诺基亚”
再编写一 个类Phone
在Phone中,组装上面的屏幕和电池,写一个方法showPhone
输出:本手机采用XX屏幕,XX电池。
主类中,请用户输入屏幕牌子,电池牌子,实例化一个Phone对象, 调用它的showPhone0方法输出屏幕和电池型号。
代码示例:
public interface Screen {
public abstract String showScreen();
}
public String showScreen() {
// TODO 自动生成的方法存根
return "索尼";
}
}
public class SAMSUNG implements Screen{
public String showScreen() {
// TODO 自动生成的方法存根
return "三星";
}
}
public interface Battery {
public abstract String showBattery();
}
public class Lenovo implements Battery{
@Override
public String showBattery() {
return "联想";
}
}
public class NOKIA implements Battery{
@Override
public String showBattery() {
return "诺基亚";
}
}
public class Phone {
// 封装
private Screen button1;
private Battery button2;
// 利用对象类的构造函数给接口的上转型对象进行赋值
public Phone(Screen button1, Battery button2) {
this.button1 = button1;
this.button2 = button2;
}
public void showPhone() {
System.out.println("本手机采用"+button1.showScreen()+"屏幕,"+button2.showBattery()+"电池");
}
}
import java.util.Scanner;
public class MainClass {
@SuppressWarnings("resource")
public static void main(String[] args) {
// TODO 自动生成的方法存根
Screen button1 = null;
Battery button2 = null;
Phone p; // 声明对象类对象
System.out.println("请输入屏幕牌子:");
String s1 = new Scanner(System.in).nextLine();
if(s1.equals("索尼"))
{
button1 = new Sony();
}
else if(s1.equals("三星"))
{
button1 = new SAMSUNG();
}
System.out.println("请输入电池牌子:");
String s2 = new Scanner(System.in).nextLine();
if(s2.equals("联想"))
{
button2 = new Lenovo();
}
else if(s2.equals("诺基亚"))
{
button2 = new NOKIA();
}
p = new Phone(button1, button2);
p.showPhone();
}
}
|