Menu
CoddyTech

Che khuất phương thức được nhúng

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 39 trên 107.

Đôi khi, bạn cần struct bên ngoài tự triển khai một phương thức mà kiểu được nhúng đã có. Đây gọi là che khuất (shadowing), giúp bạn ghi đè các phương thức được thăng cấp bằng hành vi tùy chỉnh.

Khi bạn định nghĩa một phương thức trên struct bên ngoài có cùng tên với phương thức được nhúng, phương thức bên ngoài sẽ được ưu tiên:

type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return "Some sound"
}

type Dog struct {
    Animal
    Breed string
}

func (d Dog) Speak() string {
    return "Woof!"
}

Bây giờ, khi bạn gọi Speak() trên một Dog, phương thức bên ngoài sẽ được dùng:

func main() {
    d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    
    fmt.Println(d.Speak())        // Woof!: phương thức của Dog
    fmt.Println(d.Animal.Speak()) // Some sound: phương thức của Animal
}

Phương thức được nhúng không biến mất. Bạn vẫn có thể truy cập phương thức đó một cách tường minh thông qua tên kiểu được nhúng. Cách làm này hữu ích khi bạn muốn tùy chỉnh hành vi nhưng vẫn giữ nguyên phần triển khai ban đầu, chẳng hạn như gọi phương thức đó bên trong phương thức ghi đè của bạn:

func (d Dog) Speak() string {
    return d.Animal.Speak() + " (but actually Woof!)"
}

Shadowing giúp bạn kiểm soát hành vi nào được thể hiện, đồng thời vẫn truy cập được hành vi gốc thông qua cách gọi rõ ràng.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống thông báo, trong đó các kênh thông báo khác nhau có thể tùy chỉnh cách định dạng và gửi tin nhắn. Bạn sẽ dùng cách che khuất phương thức để các kênh cụ thể ghi đè hành vi mặc định, đồng thời vẫn có thể truy cập phần triển khai ban đầu khi cần.

Bạn sẽ sắp xếp code trong ba tệp:

  • base.go: Tạo một struct BaseNotification với các trường Title và Priority (đều là chuỗi). Thêm phương thức Format() string trả về thông báo theo định dạng chuẩn: [Priority] Title.
  • channels.go: Tạo hai kiểu kênh thông báo nhúng BaseNotification và che khuất phương thức Format bằng phần triển khai riêng:
    • EmailNotification có trường Recipient. Phương thức Format() sẽ trả về Email to [Recipient]: [Priority] Title
    • SlackNotification có trường Channel. Phương thức Format() sẽ gọi phương thức BaseNotification.Format() được nhúng và thêm #[Channel]: vào đầu kết quả
  • main.go: Đọc thông tin thông báo từ đầu vào, tạo cả hai kiểu thông báo và minh họa cách che khuất bằng cách in ra:
    1. Kết quả đã định dạng của EmailNotification (dùng phương thức bị che khuất)
    2. Định dạng gốc của EmailNotification (gọi rõ ràng phương thức được nhúng)
    3. Kết quả đã định dạng của SlackNotification (bên trong có dùng phương thức gốc)

Đầu vào sẽ có dạng sau:

  • Dòng 1: Tiêu đề thông báo
  • Dòng 2: Mức độ ưu tiên
  • Dòng 3: Người nhận email
  • Dòng 4: Tên kênh Slack

Ví dụ, với Server Alert, HIGH, admin@company.com và ops-alerts, đầu ra sẽ là:

Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server Alert

Lưu ý cách EmailNotification thay thế hoàn toàn định dạng gốc, trong khi SlackNotification bổ sung vào đó bằng cách gọi phương thức ban đầu và thêm thông tin về kênh. Cả hai cách đều cho thấy những phương pháp khác nhau để sử dụng hiệu quả việc che khuất phương thức.

Tự làm thử

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Đọc tiêu đề thông báo
	scanner.Scan()
	title := scanner.Text()
	
	// Đọc mức độ ưu tiên
	scanner.Scan()
	priority := scanner.Text()
	
	// Đọc người nhận email
	scanner.Scan()
	recipient := scanner.Text()
	
	// Đọc tên kênh Slack
	scanner.Scan()
	channel := scanner.Text()
	
	// TODO: Tạo EmailNotification với thông báo cơ sở, tiêu đề, mức độ ưu tiên và người nhận
	
	// TODO: Tạo SlackNotification với thông báo cơ sở, tiêu đề, mức độ ưu tiên và kênh
	
	// TODO: In ra đầu ra đã định dạng của EmailNotification (dùng phương thức (method) ghi đè của nó)
	
	// TODO: In ra định dạng cơ sở của EmailNotification (gọi trực tiếp phương thức được nhúng)
	
	// TODO: In ra đầu ra đã định dạng của SlackNotification
	
	fmt.Println() // Phần giữ chỗ, xóa khi triển khai
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online