Go语言接口设计与模式
Go语言接口设计与模式
接口是Go语言的核心特性之一,它提供了一种灵活的方式来定义行为。本文将深入探讨Go语言接口的设计原则和常用模式。
一、接口基础
1.1 什么是接口
type Shape interface { Area() float64 Perimeter() float64 } type Rectangle struct { Width float64 Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2*r.Width + 2*r.Height } type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }1.2 接口组合
type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type Closer interface { Close() error } type ReadWriter interface { Reader Writer } type ReadWriteCloser interface { Reader Writer Closer }1.3 空接口
func printValue(v interface{}) { fmt.Printf("Type: %T, Value: %v\n", v, v) } func main() { printValue(42) printValue("hello") printValue(3.14) printValue([]int{1, 2, 3}) }二、接口设计原则
2.1 小接口原则
// 不好的设计:大接口 type BigInterface interface { Read(p []byte) (n int, err error) Write(p []byte) (n int, err error) Close() error Flush() error Seek(offset int64, whence int) (int64, error) } // 好的设计:小接口组合 type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type Closer interface { Close() error }2.2 鸭子类型
type Stringer interface { String() string } type Person struct { Name string Age int } func (p Person) String() string { return fmt.Sprintf("%s (%d)", p.Name, p.Age) } type Product struct { ID int Name string Price float64 } func (p Product) String() string { return fmt.Sprintf("Product %d: %s ($%.2f)", p.ID, p.Name, p.Price) } func printStringers(items []Stringer) { for _, item := range items { fmt.Println(item.String()) } }2.3 接口隔离
type Animal interface { Eat() Sleep() } type Flyer interface { Fly() } type Swimmer interface { Swim() } type Bird struct{} func (b Bird) Eat() { fmt.Println("Bird eating") } func (b Bird) Sleep() { fmt.Println("Bird sleeping") } func (b Bird) Fly() { fmt.Println("Bird flying") } type Fish struct{} func (f Fish) Eat() { fmt.Println("Fish eating") } func (f Fish) Sleep() { fmt.Println("Fish sleeping") } func (f Fish) Swim() { fmt.Println("Fish swimming") }三、接口模式
3.1 适配器模式
type LegacyService interface { OldMethod(data string) error } type NewService interface { NewMethod(data []byte) (int, error) } type Adapter struct { legacy LegacyService } func (a Adapter) NewMethod(data []byte) (int, error) { err := a.legacy.OldMethod(string(data)) if err != nil { return 0, err } return len(data), nil }3.2 策略模式
type SortStrategy interface { Sort(data []int) []int } type BubbleSort struct{} func (b BubbleSort) Sort(data []int) []int { result := make([]int, len(data)) copy(result, data) for i := 0; i < len(result)-1; i++ { for j := 0; j < len(result)-i-1; j++ { if result[j] > result[j+1] { result[j], result[j+1] = result[j+1], result[j] } } } return result } type QuickSort struct{} func (q QuickSort) Sort(data []int) []int { if len(data) <= 1 { return data } pivot := data[len(data)/2] var left, right []int for _, num := range data { if num < pivot { left = append(left, num) } else if num > pivot { right = append(right, num) } } left = q.Sort(left) right = q.Sort(right) return append(append(left, pivot), right...) } type Sorter struct { strategy SortStrategy } func (s *Sorter) SetStrategy(strategy SortStrategy) { s.strategy = strategy } func (s Sorter) Sort(data []int) []int { return s.strategy.Sort(data) }3.3 装饰器模式
type Logger interface { Log(message string) } type ConsoleLogger struct{} func (c ConsoleLogger) Log(message string) { fmt.Println(message) } type TimedLogger struct { logger Logger } func (t TimedLogger) Log(message string) { timestamp := time.Now().Format(time.RFC3339) t.logger.Log(fmt.Sprintf("[%s] %s", timestamp, message)) } type LeveledLogger struct { logger Logger level string } func (l LeveledLogger) Log(message string) { l.logger.Log(fmt.Sprintf("[%s] %s", l.level, message)) }3.4 工厂模式
type Transport interface { Move() } type Car struct{} func (c Car) Move() { fmt.Println("Car moving on road") } type Boat struct{} func (b Boat) Move() { fmt.Println("Boat moving on water") } type Plane struct{} func (p Plane) Move() { fmt.Println("Plane flying in sky") } type TransportFactory struct{} func (f TransportFactory) CreateTransport(transportType string) Transport { switch transportType { case "car": return Car{} case "boat": return Boat{} case "plane": return Plane{} default: return nil } }四、接口最佳实践
4.1 返回接口而非具体类型
// 不好的做法:返回具体类型 func NewDatabase() *MySQLDatabase { return &MySQLDatabase{} } // 好的做法:返回接口 func NewDatabase() Database { return &MySQLDatabase{} }4.2 使用接口进行依赖注入
type Repository interface { Get(id string) (User, error) Save(user User) error } type Service struct { repo Repository } func NewService(repo Repository) *Service { return &Service{repo: repo} } func (s *Service) GetUser(id string) (User, error) { return s.repo.Get(id) }4.3 接口测试
type MockRepository struct { users map[string]User } func (m *MockRepository) Get(id string) (User, error) { user, ok := m.users[id] if !ok { return User{}, fmt.Errorf("user not found") } return user, nil } func (m *MockRepository) Save(user User) error { m.users[user.ID] = user return nil } func TestService_GetUser(t *testing.T) { mockRepo := &MockRepository{ users: map[string]User{ "1": {ID: "1", Name: "Test"}, }, } service := NewService(mockRepo) user, err := service.GetUser("1") if err != nil { t.Fatalf("Unexpected error: %v", err) } if user.Name != "Test" { t.Errorf("Expected name 'Test', got '%s'", user.Name) } }五、接口进阶
5.1 接口类型断言
func processData(data interface{}) { switch v := data.(type) { case string: fmt.Println("String:", v) case int: fmt.Println("Integer:", v) case []int: fmt.Println("Slice of ints:", v) default: fmt.Println("Unknown type:", v) } } func getStringer(data interface{}) (Stringer, bool) { s, ok := data.(Stringer) return s, ok }5.2 接口嵌入
type Base interface { GetID() string } type Named interface { Base GetName() string } type User struct { ID string Name string } func (u User) GetID() string { return u.ID } func (u User) GetName() string { return u.Name }5.3 接口零值
func safeCall(i interface{}) { if i == nil { fmt.Println("Interface is nil") return } fmt.Println("Interface has value:", i) } func main() { var s Shape = nil safeCall(s) // Interface is nil var p *Person = nil safeCall(p) // Interface has value: <nil> }六、总结
Go语言接口是实现多态和代码解耦的关键:
- 接口定义:定义行为契约,不关心实现细节
- 设计原则:小接口、鸭子类型、接口隔离
- 设计模式:适配器、策略、装饰器、工厂
- 最佳实践:返回接口、依赖注入、接口测试
- 进阶技巧:类型断言、接口嵌入、零值处理
掌握接口设计可以编写出更灵活、更可测试的代码。
