接口的继承和抽象类

Java

Posted by 刘知安 on 2020-02-26
文章目录
  1. 0.闲谈
  2. 1.接口之间的继承
  3. 2.抽象类

0.闲谈

2020年,一场突如起来的疫情,打乱了全国千千万万人的正常生活,也很庆幸,自己在情况最危险的时候之前,离开了武汉回到了家中。所有人都强制要求不能出门,经过1个多月的最严格的全方面把控,疫情似乎逐渐正在消退,十分感激那些奋战在前线的白衣工作者和千千万工作人员,中国加油!

1.接口之间的继承

最近在做SimpleDB这个项目,让我印象很深的地方就是接口和具体实现类的设计这一块。其中,有一个点很想记下来,那就是接口的继承,原来几乎没用过这个策略。

我们都知道,接口表达的就是某个对象具有的功能,而该功能的具体实现由具体实现该接口的类来负责。

我们也知道在SQL中,大致存在两类SQL语句:① SQL查询语句 ② SQL更新语句,前者只会读取数据库表的值,而后者会修改相应值,在代码实现的时候,二者分别对应实现了Scan接口和UpdateScan接口。而Plan类中会有一个创建具体Scan对象的opne()方法。

上述的接口代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Scan {
// 移动到第一条记录之前
public void beforeFirst() throws IOException;

// 移动到下一条记录,如果没有下一条记录,返回false
public boolean next() throws IOException;

// 关闭scan,如果有subScan,也会相应关闭
public void close() throws IOException;

// 获取当前记录指定字段的值,被抽象成了一个Constant对象
public Constant getVal(String fieldName);

// 获取当前字段指定int字段的值
public int getInt(String fieldName);

// 获取当前字段指定string字段的值
public String getString(String fieldName);

// 判断是否有指定字段
public boolean hasField(String fieldName);

}

1
2
3
4
5
6
7
8
9
10
public interface UpdateScan extends Scan {
public void setVal(String fieldName,Constant newVal);
public void setInt(String fieldName,int newVal);
public void setString(String fieldName,String newVal);
public void insert() throws IOException;
public void delete();

public RID getRID();
public void moveToRId(RID rid);
}
1
2
3
4
5
6
7
public interface Plan {
public Scan open() throws IOException;
public int blockAccessed();
public int recordsOutput();
public int distinctValues(String fldName);
public Schema schema();
}

到时候,包含where子句的更新SQL语句会对应创建一个SelectPlan对象,而该对象的open()方法又会创建一个UpdateScan对象,这样一来,Plan接口可以有不同的实现,而不管具体的实现是什么,open()方法也必然会返回一个Scan对象。

此外,实现了UpdateScan接口的具体类又可能会持有一个实现了Scan接口或UpdateScan接口的实例,这样一来,就可以将该实例变量的类型声明为Scan即可,具体是什么类型,交给具体实现类去处理即可。例如SelectScan类的代码:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class SelectScan implements UpdateScan {

private Scan scan;
private Predicate predicate;

public SelectScan(Scan scan, Predicate predicate) {
this.scan = scan;
this.predicate = predicate;
}

//================Scan 接口中的方法实现===================

@Override
public void beforeFirst() throws IOException {
scan.beforeFirst();
}

@Override
public boolean next() throws IOException {
// 这里必须用while,而不是if
while (scan.next())
if (predicate.isSatisified(scan))
return true;
return false;
}

@Override
public void close() throws IOException {
scan.close();
}

@Override
public Constant getVal(String fieldName) {
return scan.getVal(fieldName);
}

@Override
public int getInt(String fieldName) {
return scan.getInt(fieldName);
}

@Override
public String getString(String fieldName) {
return scan.getString(fieldName);
}

@Override
public boolean hasField(String fieldName) {
return scan.hasField(fieldName);
}

//================UpdateScan 接口中额外的方法实现===================

@Override
public void setVal(String fieldName, Constant newVal) {
// 这里必须把scan强转为UpdateScan类型
// 也只有UpdateScan类型的对象才有setXXX()方法
// 如果scan不是一个实现了UpdateScan接口的对象,运行时则会抛出ClassCastException异常
UpdateScan updateScan = (UpdateScan) scan;
updateScan.setVal(fieldName,newVal);
}

@Override
public void setInt(String fieldName, int newVal) {
UpdateScan updateScan = (UpdateScan) scan;
updateScan.setInt(fieldName, newVal);
}

@Override
public void setString(String fieldName, String newVal) {
UpdateScan updateScan = (UpdateScan) scan;
updateScan.setString(fieldName, newVal);
}

@Override
public void insert() throws IOException {
UpdateScan updateScan = (UpdateScan) scan;
updateScan.insert();
}

@Override
public void delete() {
UpdateScan updateScan = (UpdateScan) scan;
updateScan.delete();
}

@Override
public RID getRID() {
UpdateScan updateScan = (UpdateScan) scan;
return updateScan.getRID();
}

@Override
public void moveToRId(RID rid) {
UpdateScan updateScan = (UpdateScan) scan;
updateScan.moveToRId(rid);
}
}

2.抽象类

抽象类就是有一个或多个方法没有实现的类,个人感觉,抽象类的更多的应用场景是结合了接口的。比如说某个接口HelloWorld,该接口中有2个方法,一个是输出hello world!这个字符串;还有一个方法是输出本地语言中和hello world同义的字符串。

1
2
3
4
interface HelloWorld{
public String sayHelloWorld();
public String sayLocalHelloWorld();
}

于是我们可以设计一个抽象类AbstractHelloWorld,该抽象类固定好了第一个方法sayHelloWorld()的实现,而把第二个方法的实现交给具体的实现者:
1
2
3
4
5
6
abstract class AbstractHelloWorld implements HelloWorld {
public String sayHelloWorld() {
return "hello world!";
}

}

最后,我们只要实现一个继承AbstractHelloWorld类的具体实现类即可,例如``:
1
2
3
4
5
6
public class ChineseHelloWorld extends AbstractHelloWorld {
@Override
public String sayLocalHelloWorld() {
return "你好,世界!";
}
}

说到底,抽象类就是方便程序员不要完完全全实现接口中的所有方法,抽象类将接口中那些不太会变化的方法实现好,其他程序员只要继承抽象类,去实现接口中那些经常会发生变化的方法即可(也就是抽象类中没有实现的方法)。