Interface trong Go - Cách tạo "Hợp đồng" cho Code! 📝
Chào mừng bạn đến với bài học về Interface trong Go! Trong bài học này, chúng ta sẽ tìm hiểu cách sử dụng interface để tạo ra các "hợp đồng" cho code của bạn.
Interface là gì? 🤔
Interface giống như một bản hợp đồng - nó định nghĩa những gì một type phải làm:
- Là một tập hợp các method signature
- Định nghĩa hành vi cần thiết
- Cho phép code linh hoạt và dễ mở rộng
💡 Ví dụ thực tế:
- Giống như một hợp đồng lao động
- Định nghĩa công việc cần làm
- Không quan tâm ai thực hiện
Interface Cơ Bản 🎯
1. Định nghĩa interface
type Writer interface {
Write([]byte) (int, error)
}
💡 Giải thích:
Writer
: Tên của interfaceWrite
: Method cần implement[]byte
: Dữ liệu cần ghi(int, error)
: Kết quả trả về
2. Implement interface
type File struct {
name string
}
func (f *File) Write(data []byte) (int, error) {
// Implement Write method
return len(data), nil
}
💡 Giải thích:
File
: Struct implement WriterWrite
: Method thực hiện ghi- Tự động implement interface
Interface Phổ Biến 🌟
1. Stringer - Chuyển đổi sang chuỗi
type Stringer interface {
String() string
}
💡 Giải thích:
- Chuyển đổi type sang chuỗi
- Sử dụng trong fmt.Print
- Tùy chỉnh cách hiển thị
2. Reader - Đọc dữ liệu
type Reader interface {
Read(p []byte) (n int, err error)
}
💡 Giải thích:
- Đọc dữ liệu vào buffer
- Trả về số byte đọc được
- Xử lý lỗi nếu có
3. Writer - Ghi dữ liệu
type Writer interface {
Write(p []byte) (n int, err error)
}
💡 Giải thích:
- Ghi dữ liệu từ buffer
- Trả về số byte đã ghi
- Xử lý lỗi nếu có
4. ReadWriter - Đọc và Ghi
type ReadWriter interface {
Reader
Writer
}
💡 Giải thích:
- Kết hợp Reader và Writer
- Có thể đọc và ghi
- Sử dụng interface embedding
Interface với Nhiều Method 📚
1. Shape Interface
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 + r.Height)
}
💡 Giải thích:
- Định nghĩa nhiều method
- Mỗi method có mục đích riêng
- Implement đầy đủ tất cả method
Type Assertion và Type Switch 🔄
1. Type Assertion
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Gấp đôi %v là %v\n", v, v*2)
case string:
fmt.Printf("%q dài %v ký tự\n", v, len(v))
default:
fmt.Printf("Tôi không biết kiểu %T!\n", v)
}
}
💡 Giải thích:
- Kiểm tra kiểu dữ liệu
- Xử lý theo từng kiểu
- An toàn và linh hoạt
2. Empty Interface
func printAny(v interface{}) {
fmt.Printf("Giá trị: %v\n", v)
}
💡 Giải thích:
- Chấp nhận mọi kiểu dữ liệu
- Linh hoạt nhưng cần cẩn thận
- Sử dụng khi cần thiết
Interface Embedding 🏗️
1. Kết hợp Interface
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
💡 Giải thích:
- Kết hợp nhiều interface
- Tái sử dụng code
- Dễ dàng mở rộng
Ví dụ Thực Tế 🌟
1. Logger Interface
type Logger interface {
Info(msg string)
Error(msg string)
Debug(msg string)
}
type ConsoleLogger struct{}
func (l *ConsoleLogger) Info(msg string) {
fmt.Printf("[INFO] %s\n", msg)
}
func (l *ConsoleLogger) Error(msg string) {
fmt.Printf("[ERROR] %s\n", msg)
}
func (l *ConsoleLogger) Debug(msg string) {
fmt.Printf("[DEBUG] %s\n", msg)
}
💡 Giải thích:
- Định nghĩa cách ghi log
- Dễ dàng thay đổi implementation
- Thống nhất cách ghi log
2. Payment Interface
type PaymentMethod interface {
Pay(amount float64) error
Refund(amount float64) error
}
type CreditCard struct {
Number string
}
func (c *CreditCard) Pay(amount float64) error {
// Implement payment logic
return nil
}
func (c *CreditCard) Refund(amount float64) error {
// Implement refund logic
return nil
}
💡 Giải thích:
- Định nghĩa cách thanh toán
- Hỗ trợ nhiều phương thức
- Dễ dàng mở rộng
Best Practices (Cách sử dụng tốt nhất) ✅
-
Đặt tên interface rõ ràng
// ✅ Đúng
type Writer interface {
Write([]byte) (int, error)
}
// ❌ Sai
type W interface {
W([]byte) (int, error)
} -
Giữ interface nhỏ gọn
// ✅ Đúng
type Reader interface {
Read([]byte) (int, error)
}
// ❌ Sai
type BigInterface interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
Close() error
Flush() error
// ... và nhiều method khác
} -
Implement đầy đủ
// ✅ Đúng
func (f *File) Write(data []byte) (int, error) {
return len(data), nil
}
// ❌ Sai
func (f *File) Write(data []byte) (int, error) {
return 0, nil // Thiếu xử lý
} -
Sử dụng interface cho testing
// ✅ Đúng
type Database interface {
Get(id string) (interface{}, error)
}
// ❌ Sai
type Database struct {
// Không có interface
}
Tiếp theo 🎯
Trong các bài học tiếp theo, chúng ta sẽ:
- Tìm hiểu về design patterns
- Học cách tối ưu code
- Khám phá các kỹ thuật nâng cao
- Thực hành với các dự án thực tế
💡 Lời khuyên: Hãy nghĩ về interface như một bản hợp đồng. Khi bạn định nghĩa rõ ràng những gì cần làm, code của bạn sẽ dễ dàng mở rộng và bảo trì hơn!