๊ธฐ๋ณธ ๊ฐœ๋…

์ž„๋ฒ ๋”ฉ์€ Go์—์„œ ์ƒ์†๊ณผ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๋‚ด๋Š” ๋ฐฉ๋ฒ•. ํ•˜์ง€๋งŒ ์ƒ์†์ด ์•„๋‹ˆ๋ผ ์ปดํฌ์ง€์…˜(composition).

๊ตฌ์กฐ์ฒด ์ž„๋ฒ ๋”ฉ

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

type Person struct {
    Name string
    Age  int
}

func (p Person) Greet() string {
    return "์•ˆ๋…•, ๋‚˜๋Š” " + p.Name
}

type Employee struct {
    Person    // ์ž„๋ฒ ๋”ฉ! ํƒ€์ž…๋งŒ ์“ฐ๊ณ  ํ•„๋“œ๋ช… ์—†์Œ
    Position  string
    Salary    int
}

func main() {
    emp := Employee{
        Person:   Person{Name: "๊น€์ฒ ์ˆ˜", Age: 30},
        Position: "๊ฐœ๋ฐœ์ž",
        Salary:   5000,
    }
    
    // Person์˜ ํ•„๋“œ์— ์ง์ ‘ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    fmt.Println(emp.Name)     // "๊น€์ฒ ์ˆ˜"
    fmt.Println(emp.Age)      // 30
    
    // Person์˜ ๋ฉ”์„œ๋“œ๋„ ์ง์ ‘ ํ˜ธ์ถœ ๊ฐ€๋Šฅ
    fmt.Println(emp.Greet())  // "์•ˆ๋…•, ๋‚˜๋Š” ๊น€์ฒ ์ˆ˜"
    
    // ๋ฌผ๋ก  ๋ช…์‹œ์  ์ ‘๊ทผ๋„ ๊ฐ€๋Šฅ
    fmt.Println(emp.Person.Name)   // "๊น€์ฒ ์ˆ˜"
    fmt.Println(emp.Person.Greet()) // "์•ˆ๋…•, ๋‚˜๋Š” ๊น€์ฒ ์ˆ˜"
}

๋ฉ”์„œ๋“œ ์Šน๊ฒฉ(Method Promotion)

type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return a.Name + "๊ฐ€ ์†Œ๋ฆฌ๋ƒ„"
}

func (a Animal) Move() string {
    return a.Name + "๊ฐ€ ์›€์ง์ž„"
}

type Dog struct {
    Animal
    Breed string
}

// Dog ํƒ€์ž…์— ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
func (d Dog) Bark() string {
    return d.Name + "๊ฐ€ ๋ฉ๋ฉ!"
}

// Animal์˜ ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ
func (d Dog) Speak() string {
    return d.Name + "๊ฐ€ ๋ฉ๋ฉ ์ง–์Œ"
}

func main() {
    dog := Dog{
        Animal: Animal{Name: "๋ฐ”๋‘‘์ด"},
        Breed:  "์ง„๋—๊ฐœ",
    }
    
    fmt.Println(dog.Move())  // "๋ฐ”๋‘‘์ด๊ฐ€ ์›€์ง์ž„" (Animal์—์„œ ์Šน๊ฒฉ)
    fmt.Println(dog.Speak()) // "๋ฐ”๋‘‘์ด๊ฐ€ ๋ฉ๋ฉ ์ง–์Œ" (Dog์—์„œ ์˜ค๋ฒ„๋ผ์ด๋“œ)
    fmt.Println(dog.Bark())  // "๋ฐ”๋‘‘์ด๊ฐ€ ๋ฉ๋ฉ!" (Dog ๊ณ ์œ  ๋ฉ”์„œ๋“œ)
}

๋‹ค์ค‘ ์ž„๋ฒ ๋”ฉ

type Reader struct{}
func (r Reader) Read() string { return "์ฝ๊ธฐ" }

type Writer struct{}
func (w Writer) Write() string { return "์“ฐ๊ธฐ" }

type ReadWriter struct {
    Reader
    Writer
}

func main() {
    rw := ReadWriter{}
    fmt.Println(rw.Read())  // "์ฝ๊ธฐ"
    fmt.Println(rw.Write()) // "์“ฐ๊ธฐ"
}

์ด๋ฆ„ ์ถฉ๋Œ ์‹œ ํ•ด๊ฒฐ

type A struct{}
func (a A) Method() string { return "A" }

type B struct{}
func (b B) Method() string { return "B" }

type C struct {
    A
    B
}

func main() {
    c := C{}
    
    // ์ด๊ฑด ์—๋Ÿฌ! ์–ด๋–ค Method()์ธ์ง€ ๋ชจํ˜ธํ•จ
    // fmt.Println(c.Method())
    
    // ๋ช…์‹œ์ ์œผ๋กœ ์ ‘๊ทผํ•ด์•ผ ํ•จ
    fmt.Println(c.A.Method()) // "A"
    fmt.Println(c.B.Method()) // "B"
}

์ธํ„ฐํŽ˜์ด์Šค ์ž„๋ฒ ๋”ฉ

type Reader interface {
    Read() error
}

type Writer interface {
    Write() error
}

type ReadWriter interface {
    Reader  // ์ธํ„ฐํŽ˜์ด์Šค๋„ ์ž„๋ฒ ๋”ฉ ๊ฐ€๋Šฅ
    Writer
}

// ์œ„๋Š” ์•„๋ž˜์™€ ๋™์ผ
type ReadWriter2 interface {
    Read() error
    Write() error
}

1. ๊ณตํ†ต ๊ธฐ๋Šฅ ์ถ”๊ฐ€

type Timestamp struct {
    CreatedAt time.Time
    UpdatedAt time.Time
}

func (t *Timestamp) Touch() {
    now := time.Now()
    if t.CreatedAt.IsZero() {
        t.CreatedAt = now
    }
    t.UpdatedAt = now
}

type User struct {
    Timestamp  // ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ์— ๊ณตํ†ต์œผ๋กœ ์ถ”๊ฐ€
    Name   string
    Email  string
}

type Post struct {
    Timestamp
    Title   string
    Content string
}

func main() {
    user := &User{Name: "๊น€์ฒ ์ˆ˜", Email: "kim@example.com"}
    user.Touch()  // Timestamp์˜ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ
    
    post := &Post{Title: "์ œ๋ชฉ", Content: "๋‚ด์šฉ"}
    post.Touch()  // ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
}

2. ๊ธฐ์กด ํƒ€์ž… ํ™•์žฅ

type MyString string

func (ms MyString) IsPalindrome() bool {
    s := string(ms)
    runes := []rune(s)
    for i := 0; i < len(runes)/2; i++ {
        if runes[i] != runes[len(runes)-1-i] {
            return false
        }
    }
    return true
}

type EnhancedString struct {
    MyString
}

func (es EnhancedString) Length() int {
    return len(string(es.MyString))
}

func main() {
    enhanced := EnhancedString{MyString: "level"}
    fmt.Println(enhanced.IsPalindrome()) // true
    fmt.Println(enhanced.Length())       // 5
}

์ž„๋ฒ ๋”ฉ vs ์ƒ์† ์ฐจ์ด์ 

์ƒ์† (๋‹ค๋ฅธ ์–ธ์–ด)

  • IS-A ๊ด€๊ณ„: Dog๋Š” Animal์ด๋‹ค
  • ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ ์ง€์›

์ž„๋ฒ ๋”ฉ (Go)

  • HAS-A ๊ด€๊ณ„: Employee๋Š” Person์„ ๊ฐ€์ง„๋‹ค
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ •๋จ
  • ๋” ๋ช…์‹œ์ ์ด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅ
func processAnimal(a Animal) {
    fmt.Println(a.Speak())
}

func main() {
    dog := Dog{Animal: Animal{Name: "๋ฐ”๋‘‘์ด"}}
    
    // ์ด๊ฑด ์•ˆ ๋จ! Dog๋Š” Animal์ด ์•„๋‹ˆ๋ผ Animal์„ ๊ฐ€์ง€๋Š” ๊ฒƒ
    // processAnimal(dog)
    
    // ๋ช…์‹œ์ ์œผ๋กœ Animal ๋ถ€๋ถ„์„ ์ „๋‹ฌํ•ด์•ผ ํ•จ
    processAnimal(dog.Animal)
}

์žฅ์ ๊ณผ ๋‹จ์ 

์žฅ์ 

  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ: ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๊ณต์œ 
  • ๋‹จ์ˆœํ•จ: ๋ณต์žกํ•œ ์ƒ์† ๊ณ„์ธต ์—†์Œ
  • ๋ช…์‹œ์ : ์–ด๋–ค ๊ธฐ๋Šฅ์ด ์–ด๋””์„œ ์˜ค๋Š”์ง€ ๋ช…ํ™•

๋‹จ์ 

  • ๋‹คํ˜•์„ฑ ์ œํ•œ: ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ ์–ด๋ ค์›€
  • ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ: ๊ฐ๊ฐ ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•จ