面试题答案
一键面试基于组合方式设计接口示例
假设我们有一个基础的 Writer
接口,定义如下:
type Writer interface {
Write(p []byte) (n int, err error)
}
现在我们有一个新的业务需求,需要一个 BufferedWriter
,它不仅能写数据,还能在内部维护一个缓冲区。我们可以通过组合 Writer
接口来实现:
type BufferedWriter struct {
Writer
buffer []byte
}
func (bw *BufferedWriter) Write(p []byte) (n int, err error) {
// 先将数据写入缓冲区
bw.buffer = append(bw.buffer, p...)
// 这里可以添加逻辑,当缓冲区满了再调用底层的 Writer 写入数据
return len(p), nil
}
优势
- 灵活性更高:传统继承方式下,子类紧密依赖父类,耦合度高。而组合方式允许在运行时动态替换组合的接口实现,例如
BufferedWriter
可以组合不同类型的Writer
实现,如os.Stdout
实现的Writer
接口或者网络连接实现的Writer
接口等。 - 避免多重继承问题:在传统继承中,多重继承会带来诸如菱形继承等复杂问题。而Go语言通过组合方式,不存在多重继承的困扰,代码结构更加清晰。
- 接口复用粒度更细:组合可以选择复用部分接口功能,而不是像继承那样继承整个类及其所有功能,例如
BufferedWriter
只复用了Writer
接口的Write
方法,对于其他可能存在于Writer
实现类中的非接口方法,BufferedWriter
无需关心。
劣势
- 代码量可能增加:与继承相比,通过组合实现功能可能需要更多的样板代码。例如在上述
BufferedWriter
中,需要手动实现Write
方法来调用组合的Writer
接口的Write
方法,如果有多个方法需要转发,代码量会有所增加。 - 关系不够直观:继承方式能很直观地看出类之间的层次关系,而组合方式对于类之间的关系理解相对需要更多的代码阅读,尤其是对于复杂的组合结构,理解成本稍高。