示例代码:
type IClient interface {
UploadFile(sourcePath, host string) error
CopyFile(sourcePath, destPath string) error
DeleteFile(sourcePath, option string) error
GetChecksum(sourcePath string) (*string, error)
GetSize(sourcePath string) (*float32, error)
}
type FileWorker struct {
Extension string
Host string
}
func NewFileWorker(fileExtension, host string) IClient {
var fileWorker = &FileWorker {
Extension: extension,
Host: host,
}
return fileWorker
}
//NOTE: type FileWorker is the receiver of all methods implementing the IClient interface
我见过其他";新的";(或"Get"(函数返回接口。但它实际上并没有返回接口,而是返回一个实现所述接口的结构。反过来,该结构类型是实现所述接口的各种方法的接收器。
问题:我们何时以及为什么返回接口?目前,我认为这是一种迂回的做事方式,导致在试图理解一些代码的同时,必须追溯多个文件。
接口是实现代码重用的一种方式。通常情况下,重要的不是物体是什么,而是它的作用。考虑以下方法:
func Grade(questions []MultipleChoiceQuestion) {
total := len(questions)
correct := 0
for _, q := range questions {
if q.Test() {
correct++
}
}
return correct / total
}
函数Grade
接收一组问题并对用户的答案进行评分。
如果我们想添加正确或错误的问题呢?现在Grade
只接受MultipleChoiceQuestions,这意味着我们必须制作一个全新的函数,比如GradeTrueOrFalse(questions []TrueOrFalseQuestions)
,才能用真问题或假问题进行测试。此外,我们将无法进行由多项选择题和真题或假题组成的测试。
然而,我们应该能够在一次测试中组合问题。原来的函数并不关心它是什么样的问题,只关心这个问题可以测试((用户的答案。这就是接口的用武之地
通过将Test
方法抽象为一个接口,我们可以对任何类型的问题使用Grade
。
type Tester interface {
Test() bool
}
type MultipleChoiceQuestion struct
func (q MultipleChoiceQuestion) Test() bool {
// implementation...
}
type TrueOrFalseQuestion struct
func (q TrueOrFalseQuestion) Test() bool {
// implementation...
}
func Grade(questions []Tester) {
total := len(questions)
correct := 0
for _, q := range questions {
if q.Test() {
correct++
}
}
return correct / total
}
现在Grade可以回答任何问题。此外,questions []Tester
可以是多选题和对错题的混合。
如果使用得当,您应该很少需要执行类型断言或";通过多个文件回溯";了解发生了什么。