抽象类的例子

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
// 抽象类
public abstract class Logger {
private String name;
private boolean enabled;
private Level minPermittedLevel;

public Logger(String name, boolean enabled, Level minPermittedLevel) {
this.name = name;
this.enabled = enabled;
this.minPermittedLevel = minPermittedLevel;
}

public void log(Level level, String message) {
boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intVal)
if (!loggable) return;
doLog(level, message);
}

protected abstract void doLog(Level level, String message);
}

// 抽象类的子类:输出日志到文件
public class FileLogger extends Logger {
private Writer fileWriter;
public FileLogger(String name, boolean enabled, Level minPermittedLevel, String filepath) {
super(name, enabled, minPermittedLevel);
this.fileWriter = new FileWriter(filepath);
}

@Override
public void doLog(Level level, String mesage) {
// 格式化 level 和 message, 输出到日志文件
fileWriter.write(...);
}
}

// 抽象类的子类: 输出日志到消息中间件 (比如 kafka)
public class MessageQueueLogger extends Logger {
private MessageQueueClient msgQueueClient;
public MessageQueueLogger(String name, boolean enabled,
Level minPermittedLevel, MessageQueueClient msgQueueClient) {
super(name, enabled, minPermittedLevel);
this.msgQueueClient = msgQueueClient;
}
@Override
protected void doLog(Level level, String mesage) {
// 格式化 level 和 message, 输出到消息中间件
msgQueueClient.send(...);
}
}

抽象类不允许被实例化,只能被继承。也就是说,你不能 new 一个抽象类的对象出来 (Logger logger = new Logger(…); 会报编译错误)。

抽象类可以包含属性和方法。方法既可以包含代码实现(比如 Logger 中的 log() 方 法),也可以不包含代码实现(比如 Logger 中的 doLog() 方法)。不包含代码实现的 方法叫作抽象方法。

子类继承抽象类,必须实现抽象类中的所有抽象方法。对应到例子代码中就是,所有继 承 Logger 抽象类的子类,都必须重写 doLog() 方法。

接口的例子

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
// 接口
public interface Filter {
void doFilter(RpcRequest req) throws RpcException;
}
// 接口实现类:鉴权过滤器
public class AuthencationFilter implements Filter {
@Override
public void doFilter(RpcRequest req) throws RpcException {
//... 鉴权逻辑..
}
}
// 接口实现类:限流过滤器
public class RateLimitFilter implements Filter {
@Override
public void doFilter(RpcRequest req) throws RpcException {
//... 限流逻辑...
}
}
// 过滤器使用 demo
public class Application {
// filters.add(new AuthencationFilter());
// filters.add(new RateLimitFilter());
private List<Filter> filters = new ArrayList<>();
public void handleRpcRequest(RpcRequest req) {
try {
for (Filter filter : fitlers) {
filter.doFilter(req);
}
} catch(RpcException e) {
// ... 处理过滤结果...
}
// ... 省略其他处理逻辑...
}
}

接口不能包含属性(也就是成员变量)。

接口只能声明方法,方法不能包含代码实现。

类实现接口的时候,必须实现接口中声明的所有方法.

区别

接口和抽象类,他们要解决的问题不一样 ,首先接口是为了解耦,而抽象类是为了减少编写重复的代码。

比如说类A和类B都要写一个方法doSomething,那么就可以写一个抽象类,然后A和B都继承该抽象类,而且类A和B可以各自添加各自的功能。

而接口的解耦体现在,我们定义一个接口之后,他可以有多个实现,我们基于他不同的实现来达到对于模块的划分,隔离接口和具体的实现,提高代码的扩展性。

参考

《设计模式之美》