Go Academy · บทเรียน

การประกอบ interface และแนวทางปฏิบัติที่ดี

interface ขนาดเล็กและการกลับทิศทางดีเพนเดนซี

บทเรียน 4 จาก 413 ขั้นตอน

การประกอบ interface และแนวทางปฏิบัติที่ดี เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

การประกอบอินเทอร์เฟซ

อินเทอร์เฟซของ Go สามารถฝังอินเทอร์เฟซอื่นเพื่อประกอบเป็นอินเทอร์เฟซที่มีขนาดใหญ่ขึ้นได้:

package main
import "io"

// io.ReadWriter composes Reader and Writer
type ReadWriter interface {
    io.Reader
    io.Writer
}

// Your own composition:
type Processor interface {
    io.Reader
    Process() error
    io.Closer
}

func main() { _ = (*Processor)(nil) }

หลักการอินเทอร์เฟซขนาดเล็ก

อินเทอร์เฟซของ Go ที่ทรงพลังที่สุดมักมีเมธอดหนึ่งหรือสองรายการ ซึ่งทำให้มีชนิดข้อมูลจำนวนมากที่สุดที่สามารถทำตามอินเทอร์เฟซนั้นได้:

  • io.Reader — 1 เมธอด
  • io.Writer — 1 เมธอด
  • error — 1 เมธอด
  • fmt.Stringer — 1 เมธอด

อินเทอร์เฟซขนาดใหญ่สร้างตัวจำลองและทำการทดสอบได้ยากกว่า

การกลับทิศทางการพึ่งพา

รับอินเทอร์เฟซในพารามิเตอร์ของฟังก์ชันแทนชนิดข้อมูลรูปธรรม วิธีนี้ทำให้โค้ดไม่ผูกติดกับการนำไปใช้งานเฉพาะแบบ:

package main
import "fmt"

type Store interface {
    Get(key string) (string, bool)
    Set(key, val string)
}

func cache(s Store, key, value string) {
    if _, ok := s.Get(key); !ok {
        s.Set(key, value)
    }
}

type MapStore struct{ m map[string]string }
func (ms *MapStore) Get(k string) (string, bool) { v, ok := ms.m[k]; return v, ok }
func (ms *MapStore) Set(k, v string) { ms.m[k] = v }

func main() {
    s := &MapStore{m: map[string]string{}}
    cache(s, "x", "hello")
    v, _ := s.Get("x")
    fmt.Println(v)
}

การแยกอินเทอร์เฟซ

แยกอินเทอร์เฟซขนาดใหญ่ออกเป็นอินเทอร์เฟซขนาดเล็กที่มุ่งเน้นเฉพาะด้าน ผู้เรียกใช้จะพึ่งพาเฉพาะเมธอดที่ตนใช้งาน:

package main

// Bad: large interface forces all methods
type BigStorage interface {
    Read(key string) string
    Write(key, val string)
    Delete(key string)
    List() []string
    Backup() error
}

// Good: small, focused interfaces
type Reader interface{ Read(key string) string }
type Writer interface{ Write(key, val string) }
type Lister interface{ List() []string }

func readAll(r Reader) {} // only needs Read

func main() { _ = readAll }

การคืนค่าชนิดข้อมูลรูปธรรม

ฟังก์ชันสร้างควรคืนค่าชนิดข้อมูลรูปธรรม ไม่ใช่อินเทอร์เฟซ ผู้เรียกใช้สามารถกำหนดชนิดข้อมูลรูปธรรมให้กับตัวแปรอินเทอร์เฟซได้เสมอ:

package main

type Logger interface{ Log(string) }
type ConsoleLogger struct{}
func (c *ConsoleLogger) Log(s string) {}

// Good: return concrete *ConsoleLogger
func NewConsoleLogger() *ConsoleLogger { return &ConsoleLogger{} }

// Avoid: return Logger (hides the concrete type)
// func NewConsoleLogger() Logger { return &ConsoleLogger{} }

func main() { _ = NewConsoleLogger() }

การสร้างอินเทอร์เฟซมากเกินไป

อย่าสร้างอินเทอร์เฟซให้ทุกชนิดข้อมูลเพียงเพราะอาจต้องใช้ในอนาคต สร้างอินเทอร์เฟซเฉพาะเมื่อ:

  • ตอนนี้หรือในเร็ว ๆ นี้มีการนำไปใช้งานหลายแบบ
  • จำเป็นต้องสร้างตัวจำลองของสิ่งที่พึ่งพาในการทดสอบ
  • กำลังสร้างไลบรารีและต้องการแยกผู้เรียกใช้ออกจากรายละเอียดการนำไปใช้งาน

การฝังอินเทอร์เฟซเพื่อขยายการทำงาน

ฝังอินเทอร์เฟซเพื่อเพิ่มเมธอดเสริมที่มีการทำงานเริ่มต้น:

package main
import "fmt"

type Handler interface{ Handle(msg string) }
type NamedHandler interface {
    Handler
    Name() string
}

func dispatch(h Handler) {
    if nh, ok := h.(NamedHandler); ok {
        fmt.Printf("[%s] ", nh.Name())
    }
    h.Handle("event")
}

type MyHandler struct{}
func (m MyHandler) Handle(msg string)  { fmt.Println(msg) }
func (m MyHandler) Name() string       { return "my" }

func main() { dispatch(MyHandler{}) }

การสร้างตัวจำลองด้วยอินเทอร์เฟซ

กำหนดสิ่งที่พึ่งพาเป็นอินเทอร์เฟซ แล้วใส่ตัวจำลองในการทดสอบ:

package main
import "fmt"

type Clock interface{ Now() int64 }

type MockClock struct{ T int64 }
func (m MockClock) Now() int64 { return m.T }

func isExpired(c Clock, expiresAt int64) bool {
    return c.Now() > expiresAt
}

func main() {
    mc := MockClock{T: 1000}
    fmt.Println(isExpired(mc, 500))  // true
    fmt.Println(isExpired(mc, 1500)) // false
}

การฝังอินเทอร์เฟซเทียบกับการฝังโครงสร้างเพื่อใช้ซ้ำ

ใช้การฝังอินเทอร์เฟซเพื่อประกอบส่วนติดต่อการใช้งาน และใช้การฝังโครงสร้างเพื่อใช้โค้ดซ้ำ ทั้งสองมีจุดประสงค์ต่างกันและไม่ควรสับสนกัน

การตรวจสอบการทำตามอินเทอร์เฟซขณะคอมไพล์

ใช้การตรวจสอบขณะคอมไพล์ด้วยตัวระบุว่าง เพื่อยืนยันว่าชนิดข้อมูลของคุณทำตามอินเทอร์เฟซที่กำหนด:

package main

type Doer interface{ Do() }
type MyType struct{}
func (m *MyType) Do() {}

// Compile-time check — no runtime cost
var _ Doer = (*MyType)(nil)

func main() {}

ตรวจสอบอย่างรวดเร็ว

คุณควรกำหนดอินเทอร์เฟซใหม่ใน Go เมื่อใด

สรุปทบทวน: แนวทางปฏิบัติที่ดีสำหรับอินเทอร์เฟซ

ประเด็นสำคัญ:

  • ทำให้อินเทอร์เฟซมีขนาดเล็ก — มีเมธอดหนึ่งหรือสองรายการ
  • ประกอบอินเทอร์เฟซจากอินเทอร์เฟซขนาดเล็ก
  • รับอินเทอร์เฟซและคืนค่าชนิดข้อมูลรูปธรรม
  • สร้างอินเทอร์เฟซเพื่อให้ทดสอบได้และรองรับการนำไปใช้งานหลายแบบ
  • ใช้การตรวจสอบด้วยการกำหนดค่าให้ตัวระบุว่างขณะคอมไพล์

โจทย์ฝึกปฏิบัติ

ออกแบบอินเทอร์เฟซ Notifier ที่มี Notify(msg string) error แล้วนำไปใช้กับ EmailNotifier และ SMSNotifier เขียนฟังก์ชัน broadcast ที่ส่งข้อความไปยัง []Notifier

เริ่มต้นได้ฟรี

เรียนรู้ Go ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

คำถามที่พบบ่อย

บทเรียน “การประกอบ interface และแนวทางปฏิบัติที่ดี” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การประกอบ interface และแนวทางปฏิบัติที่ดี” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การประกอบ interface และแนวทางปฏิบัติที่ดี”

interface ขนาดเล็กและการกลับทิศทางดีเพนเดนซี คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การประกอบ interface และแนวทางปฏิบัติที่ดี” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม

ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การกำหนดและใช้งาน interface
  2. interface ของไลบรารีมาตรฐานหลัก
  3. การยืนยันชนิดข้อมูลและสวิตช์ชนิดข้อมูล
  4. การประกอบ interface และแนวทางปฏิบัติที่ดี
← กลับไปที่ Go Academy