从图形处理类看继承和多态

各类图形.jpg

上图有一些基本的图形。接下来,用以下类来定义图形:

  • 父类Shape,表示图形

  • 类Circle,表示圆

  • 类Line,表示直线

  • 类ArrowLine,表示带箭头的直线

图形Shape类有一个表示颜色的属性,和一个表示绘制的方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//父类:图形类
public class Shape {

private static final String DEFAULT_COLOR = "black";
private String color;

public Shape() {
this(DEFAULT_COLOR);
}

public Shape(String color) {
this.color = color;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

public void draw() {
System.out.println("draw shape");
}
}

圆circle类继承自Shape,但包括了Shape没有的中心点和半径属性,以及额外的方法area,用于计算面积。

此外又重写了draw方法。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Circle extends Shape {
//中心点
private Point center;
//半径
private double r;

public Circle(Point center,double r) {
this.center = center;
this.r = r;
}

@Override
public void draw() {
System.out.println("draw circle at "+center.toString()+" with r "
+r+", using color : "+getColor());
}

public double area() {
return Math.PI*r*r;
}
}

直线Line类继承Shape类,它有两个点,有一个获取长度的方法,并且重写了draw方法。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Line extends Shape {
private Point start;
private Point end;

public Line(Point start,Point end,String color) {
super(color);
this.start = start;
this.end = end;
}

public double length() {
return start.distance(end);
}

public Point getStart() {
return start;
}

public Point getEnd() {
return end;
}

@Override
public void draw() {
System.out.println("draw line from "+ start.toString() + " to "
+end.toString()+",using color "+super.getColor());
}
}

带箭头直线ArrowLine类继承自Line类,多了表示两端是否有箭头的两个属性,也重写了draw方法。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ArrowLine extends Line{
//起点是否有箭头
private boolean startArrow;
//终点是否有箭头
private boolean endArrow;

public ArrowLine(Point start,Point end,String color,
boolean startArrow,boolean endArrow) {
super(start,end,color);
this.startArrow = startArrow;
this.endArrow = endArrow;
}

@Override
public void draw() {
super.draw();
if (startArrow) {
System.out.println("draw start arrow");
}
if (endArrow) {
System.out.println("draw end arrow");
}
}
}

super.draw();表示调用父类的draw()方法。

使用继承的一个好处是可以统一处理不同子类型的对象。

比如说,设计一个图形管理ShapeManager类,它负责管理画板上的所有图形对象并负责绘制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ShapeManager {
//图形最大个数为100
private static final int MAX_NUM = 100;
private Shape[] shapes = new Shape[MAX_NUM];
private int shapeNum = 0;

public void addShape(Shape shape) {
if (shapeNum < MAX_NUM) {
shapes[shapeNum++] = shape;
}
}

public void draw() {
for (int i=0;i<shapeNum;i++) {
shapes[i].draw();
}
}
}

如上方代码,ShapeManager使用一个数组保存所有的shape,在draw方法中调用每个shape的draw方法。

接下来使用ShapeManager:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
ShapeManager manager = new ShapeManager();

manager.addShape(new Circle(new Point(4,4),3)); //添加圆形
manager.addShape(new Line(new Point(2,3),new Point(3,4),"green")); //添加直线
manager.addShape(new ArrowLine(new Point(1,2),new Point(5,5),"black",false,false)); //添加箭头线

manager.draw();
}

新建了三个图形,分别是一个圆、直线、箭头线,然后加到ShapeManager中,再调用manager的draw方法。

在addShape方法中,参数Shape shape,声明的类型是Shape,而实际的类型则分别是Circle、Line、ArrowLine。子类对象赋值给父类引用变量,叫做向上转型,转型=转换类型,向上转型=转换为父类类型。

变量Shape可以引用任何Shape子类类型的对象,称为多态,即一种类型的变量,可引用多种实际类型对象

对于变量shape,它有两个类型,类型Shape,我们称之为shape的静态类型;类型Circle/Line/ArrowLine,我们称之为shape的动态类型

在ShapeManager的draw方法中,shapes[i].draw()调用的是其对应动态类型的draw方法,这称之为方法的动态绑定

为什么要有多态和动态绑定呢?创建对象的代码 (ShapeManager以外的代码)和操作对象的代码(ShapeManager本身的代码),经常不在一起,操作对象的代码往往只知道对象是某种父类型,也往往只需要知道它是某种父类型就可以了。

多态和动态绑定是计算机程序中的一种重要思维方式,使得操作对象的程序不需要关注对象的实际类型,从而可以统一处理不同对象,但又能实现每个对象的特有行为。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021 Silver Shaded
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信