GoSuda

Go-interfaces zijn geen overerving

By Yunjin Lee
views ...

κ°œμš”

Go μΈν„°νŽ˜μ΄μŠ€λŠ” λ™μΌν•œ μΈμžμ™€ λ°˜ν™˜κ°’μ„ κ°–λŠ” ν•¨μˆ˜λ₯Ό μ—¬λŸ¬ κ΅¬μ‘°μ²΄μ—μ„œ μ‰½κ²Œ κ°€μ§ˆ 수 있게 ν•˜μ§€λ§Œ, java의 extends ν‚€μ›Œλ“œμ²˜λŸΌ κ·Έ λ‚΄λΆ€ ν•¨μˆ˜μ˜ λ™μž‘κΉŒμ§€ 적절히 μ—°μž₯ν•˜κ³  μ˜€λ²„λΌμ΄λ“œν•˜λŠ” λ°©μ‹κ³ΌλŠ” λ‹€λ¦…λ‹ˆλ‹€. Go의 ꡬ성적 μ½”λ“œ μž¬μ‚¬μš©μ„ μ œλŒ€λ‘œ μ΄ν•΄ν•΄μ•Όλ§Œ 상속과 ν—·κ°ˆλ¦¬μ§€ μ•Šκ² μ§€λ§Œ, μ²˜μŒλΆ€ν„° 이둠적으둜 μ™„λ²½ν•œ 이해λ₯Ό ν•˜λŠ” 것은 μ–΄λ ΅μŠ΅λ‹ˆλ‹€. μ‹€μˆ˜ν•˜κΈ° 쒋은 μ‹œλ‚˜λ¦¬μ˜€μ™€ ν•¨κ»˜ μ•Œμ•„λ΄…μ‹œλ‹€.

자주 ν•˜λŠ” μ‹€μˆ˜

μ΄ˆμ‹¬μž 뢄듀은 λ‹€μŒκ³Ό 같은 μ‹€μˆ˜λ₯Ό ν•˜μ‹€ 수 μžˆμŠ΅λ‹ˆλ‹€.

 1package main
 2import (
 3	"fmt"
 4	"strings"
 5)
 6
 7type Fruits interface {
 8	GetBrix() float64
 9	GetName() string
10	SetLabel()
11	GetLabel(string) string
12	PrintAll()
13}
14
15type Apple struct {
16	Label string
17	Name  string
18	Brix  float64
19}
20
21type Watermelon struct {
22	Label string
23	Name  string
24	Brix  float64
25}
26
27func (a *Apple) PrintAll() {
28	fmt.Printf("Fruit: %s, Label: %s, Brix: %v\n", a.Name, a.Label, a.Brix)
29}
30
31const (
32	NO_LABEL = "EMPTY LABEL"
33)
34
35func (a *Apple) SetLabel(lbl string) {
36	a.Brix 	= 14.5;
37	a.Name 	= "apple";
38	lbl_lower := strings.ToLower(lbl)
39	if strings.Contains(lbl_lower, a.Name) {
40		fmt.Println("Succeed: Label was ", lbl)
41		a.Label = lbl;
42	} else {
43		fmt.Println("Failed: Label was ", lbl)
44		a.Label = NO_LABEL;
45	}
46}
47
48func (w *Watermelon) SetLabel(lbl string) {
49	w.Brix = 10;
50	w.Name = "watermelon";
51	lbl_lower := strings.ToLower(lbl)
52	if strings.Contains(lbl_lower, w.Name) {
53		w.Label = lbl;
54	} else {
55		w.Label = NO_LABEL;
56	}
57}
58
59func main() {
60	fmt.Println("Inheritance test #1")
61	apple := new(Apple)
62	watermelon := apple
63	apple.SetLabel("Apple_1")
64	fmt.Println("Apple, before copied to Watermelon")
65	apple.PrintAll()
66	watermelon.SetLabel("WaterMelon_2")
67	fmt.Println("Apple, after copied to Watermelon")
68	apple.PrintAll()
69	fmt.Println("Watermelon, which inherited Apple's Method")
70	watermelon.PrintAll()
71}

μ΄λŸ¬ν•œ μ½”λ“œλŠ” Goκ°€ 전톡적인 상속을 λ”°λ₯Έλ‹€κ³  μ°©κ°ν•˜λ©΄ λ¬Έμ œκ°€ μ—†μ–΄ λ³΄μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ΄κ²ƒμ˜ 좜λ ₯ κ²°κ³ΌλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

1Inheritance test #1
2Succeed: Label was  Apple_1
3Apple, before copied to Watermelon
4Fruit: apple, Label: Apple_1, Brix: 14.5
5Failed: Label was  WaterMelon_2
6Apple, after copied to Watermelon
7Fruit: apple, Label: EMPTY LABEL, Brix: 14.5
8Watermelon, which inherited Apple's Method
9Fruit: apple, Label: EMPTY LABEL, Brix: 14.5

μ—¬κΈ°μ„œ Go의 λ™μž‘μ€ λ‹€λ§Œ λͺ…ν™•ν•΄μ§‘λ‹ˆλ‹€.

1watermelon := apple

이 μ½”λ“œλŠ” μ „ν˜€ Apple을 κ·ΈλŒ€λ‘œ Watermelon 클래슀둜 λ³€ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‹€λ§Œ watermelon은 apple에 λŒ€ν•œ 포인터일 λΏμž…λ‹ˆλ‹€.

μ—¬κΈ°μ„œ λ‹€μ‹œ κ°•μ‘°ν•˜μ§€λ§Œ, GoλŠ” 전톡적인 상속 κ°œλ…μ„ λ”°λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ΄λŸ¬ν•œ μ˜€ν•΄λ₯Ό ν•œ μƒνƒœμ—μ„œ μ½”λ“œλ₯Ό μ§ λ‹€λ©΄ λ¬΄μ˜λ―Έν•œ 포인터 생성, 예기치 λͺ»ν•œ 타 ꡬ쑰체λ₯Ό μœ„ν•œ ν•¨μˆ˜ 볡사 λ“±μ˜ 치λͺ…적 였λ₯˜κ°€ μƒκΉλ‹ˆλ‹€.

κ·Έλ ‡λ‹€λ©΄ λͺ¨λ²”적인 μ½”λ“œλŠ” μ–΄λ– ν• κΉŒμš”?

Goμ–Έμ–΄μ—μ„œ μ μ ˆν•œ μ˜ˆμ‹œ

 1package main
 2import (
 3	"fmt"
 4	"strings"
 5)
 6
 7type Fruits interface {
 8	GetBrix() float64
 9	GetName() string
10	SetLabel()
11	GetLabel(string) string
12	PrintAll()
13}
14
15type BaseFruit struct {
16	Name  string
17	Brix  float64
18}
19
20type Apple struct {
21	Label string
22	Fruit BaseFruit
23}
24
25type Watermelon struct {
26	Label string
27	Fruit BaseFruit
28
29}
30
31func (b *BaseFruit) PrintAll() {
32	fmt.Printf("Fruit: %s, Brix: %v\n", b.Name, b.Brix)
33}
34
35
36const (
37	NO_LABEL = "EMPTY LABEL"
38)
39
40func (a *Apple) SetLabel(lbl string) {
41	a.Fruit.Brix 	= 14.5;
42	a.Fruit.Name 	= "apple";
43	lbl_lower := strings.ToLower(lbl)
44	if strings.Contains(lbl_lower, a.Fruit.Name) {
45		fmt.Println("Succeed: Label was ", lbl)
46		a.Label = lbl;
47	} else {
48		fmt.Println("Failed: Label was ", lbl)
49		a.Label = NO_LABEL;
50	}
51	fmt.Printf("Fruit %s label set to %s\n", a.Fruit.Name, a.Label);
52	a.Fruit.PrintAll()
53}
54
55func (w *Watermelon) SetLabel(lbl string) {
56	w.Fruit.Brix = 10;
57	w.Fruit.Name = "Watermelon";
58	lbl_lower := strings.ToLower(lbl)
59	if strings.Contains(lbl_lower, w.Fruit.Name) {
60		w.Label = lbl;
61	} else {
62		w.Label = NO_LABEL;
63	}
64	fmt.Printf("Fruit %s label set to %s\n", w.Fruit.Name, w.Label);
65	w.Fruit.PrintAll()
66}
67
68func main() {
69	apple := new(Apple)
70	watermelon := new(Watermelon)
71	apple.SetLabel("Apple_1")
72	watermelon.SetLabel("WaterMelon_2")
73}

κ·ΈλŸ¬λ‚˜, Goμ—μ„œλ„ μƒμ†μ²˜λŸΌ 보이게 ν•˜λŠ” 것은 κ°€λŠ₯ν•©λ‹ˆλ‹€. 읡λͺ… μž„λ² λ”©μ΄λΌλŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€. 이것은 λ‚΄λΆ€ ꡬ쑰체λ₯Ό 이름 μ—†λŠ” ꡬ쑰체둜 μ„ μ–Έν•˜λ©΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” ν•˜μœ„ ꡬ쑰체의 ν•„λ“œλ“€μ„ λͺ…μ‹œ 없이 μ‚¬μš©ν•΄λ„ κ·ΈλŒ€λ‘œ 접근이 κ°€λŠ₯ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜μœ„ ꡬ쑰체의 ν•„λ“œλ₯Ό μƒμœ„ ꡬ쑰체둜 μŠΉκ²©ν•˜λŠ” νŒ¨ν„΄μ„ μ΄μš©ν•˜λ©΄ κ²½μš°μ— 따라 κ°€λ…μ„±μ˜ ν–₯상이 κ°€λŠ₯ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ ν•˜μœ„ ꡬ쑰체λ₯Ό λͺ…μ‹œμ μœΌλ‘œ λ³΄μ—¬μ€˜μ•Ό ν•˜λŠ” κ²½μš°μ—λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠκΈ°λ₯Ό ꢌμž₯ν•©λ‹ˆλ‹€.

 1package main
 2import (
 3	"fmt"
 4	"strings"
 5)
 6
 7type Fruits interface {
 8	GetBrix() float64
 9	GetName() string
10	SetLabel()
11	GetLabel(string) string
12	PrintAll()
13}
14
15type BaseFruit struct {
16	Name  string
17	Brix  float64
18}
19
20type Apple struct {
21	Label string
22	BaseFruit
23}
24
25type Watermelon struct {
26	Label string
27	BaseFruit
28
29}
30
31func (b *BaseFruit) PrintAll() {
32	fmt.Printf("Fruit: %s, Brix: %v\n", b.Name, b.Brix)
33}
34
35
36const (
37	NO_LABEL = "EMPTY LABEL"
38)
39
40func (a *Apple) SetLabel(lbl string) {
41	a.Brix 	= 14.5;
42	a.Name 	= "apple";
43	lbl_lower := strings.ToLower(lbl)
44	if strings.Contains(lbl_lower, a.Name) {
45		fmt.Println("Succeed: Label was ", lbl)
46		a.Label = lbl;
47	} else {
48		fmt.Println("Failed: Label was ", lbl)
49		a.Label = NO_LABEL;
50	}
51	fmt.Printf("Fruit %s label set to %s\n", a.Name, a.Label);
52	a.PrintAll()
53}
54
55func (w *Watermelon) SetLabel(lbl string) {
56	w.Brix = 10;
57	w.Name = "Watermelon";
58	lbl_lower := strings.ToLower(lbl)
59	if strings.Contains(lbl_lower, w.Name) {
60		w.Label = lbl;
61	} else {
62		w.Label = NO_LABEL;
63	}
64	fmt.Printf("Fruit %s label set to %s\n", w.Name, w.Label);
65	w.PrintAll()
66}
67
68func main() {
69	apple := new(Apple)
70	watermelon := new(Watermelon)
71	apple.SetLabel("Apple_1")
72	watermelon.SetLabel("WaterMelon_2")
73}

이 μ˜ˆμ‹œμ—μ„œλŠ” μ΄λŸ¬ν•œ 차이점이 μžˆμŠ΅λ‹ˆλ‹€.

1w.PrintAll() // w.Friut.PrintAll()이 μ•„λ‹Œ, 이름 μ—†λŠ” ꡬ쑰체λ₯Ό ν†΅ν•œ μžλ™ 승격 호좜

두 예제 λͺ¨λ‘ μ€‘μš”ν•œ 지점은 μ΄λŸ¬ν•©λ‹ˆλ‹€.

  • main은 κ°„μ†Œν•˜κ²Œ, ν•¨μˆ˜λŠ” κΈ°λŠ₯ λ³„λ‘œ
  • λ‹€λ₯Έ ꡬ쑰체라면 λ‹€λ₯Έ 객체λ₯Ό
  • κ³΅μœ κ°€ ν•„μš”ν•  경우 λ‚΄λΆ€ ꡬ쑰체λ₯Ό μ‚¬μš©

이와 같은 ν”„λ‘œκ·Έλž˜λ° 철학에 μ–΄λ– ν•œ 이점이 μžˆμ„κΉŒμš”?

이점

  • κ³΅μœ κ°€ ν•„μš”ν•œ λ©”μ„œλ“œμ™€ μ•„λ‹Œ κ²ƒμ˜ ꡬ별 λͺ…ν™•
  • κ°œλ³„ ꡬ쑰체, λ©”μ„œλ“œμ— μ±…μž„ μ†Œμž¬ 뢄리
  • ν•„μš”ν•œ κΈ°λŠ₯ λͺ…세에 따라 ꡬ쑰적으둜 λΆ„λ¦¬λœ μ½”λ“œ

μ²˜μŒμ—λŠ” Goμ–Έμ–΄λŠ” 전톡적인 OOP와 달라 μ΅μˆ™ν•˜μ§€ μ•Šμ„ 수 μžˆμœΌλ‚˜, μ΅μˆ™ν•΄μ§€λ©΄ λͺ…μ‹œμ μΈ ν”„λ‘œκ·Έλž˜λ°μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.

μš”μ•½

  • μ±…μž„ μ†Œμž¬λ₯Ό κ³ λ¦½μ‹œν‚€μž
  • ꡬ쑰체 λ‹¨μœ„λ‘œ μ„ΈλΆ€μ μœΌλ‘œ λ‚˜λˆ„μž
  • λ©”μ„œλ“œλŠ” μžλ°”μ˜ abstract class zoals niet begrepen moet worden
  • λͺ…μ‹œμ μ΄κ³  ꡬ체적인 ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜μž Goμ–Έμ–΄λŠ” 전톡적인 OOP λͺ¨λΈλ³΄λ‹€ 간단λͺ…λ£Œν•˜κ³  κ°œλ³„μ μœΌλ‘œ 닀뀄져야 ν•©λ‹ˆλ‹€. ν™•μž₯적이게 ν”„λ‘œκ·Έλž˜λ°ν•˜κΈ°λ³΄λ‹€ 단계적이고 ꡬ쑰적으둜 λΆ„λ¦¬ν•˜μ—¬ μž‘μ„±ν•˜λ„λ‘ ν•©μ‹œλ‹€.