Recent Comments
Link
Recent Posts
Today
Total
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
관리 메뉴

Study Memory Work

[Go Lang] 인터페이스 본문

Programing/Go

[Go Lang] 인터페이스

Hera Choi 2023. 3. 2. 18:16

인터페이스

  • 객체의 동작을 표현, 골격
  • 단순히 동작에 대한 방법만 표기
  • 추상화 제공
  • 인터페이스의 메소드를 구현한 타입은 이터페이스로 사용 가능
  • Go 언어를 유연하게 사용 가능

 

  • 덕타이핑 : Go언어의 독창적인 특성

 

  • 인터페이스를 왜 사용하는지??
    -> 자바의(전략패턴, 템플릿메소드, 팩토리메소드패턴, 어댑터패턴 .....) 디자인 패턴 측면에서볼 때,
    메소드를 호출하는 클라이언트 입장에서 사용하는 메소드의 구체적인 클래스를 몰라도
    인터페이스에 정의된 메소드를 사용하는 객체 보장.
    클래스의 수정이 일어나도 메소드를 따로 수정할 필요 없음.
    ==> 클래스 간의 결합도를 낮춰줌 -> 유지보수 용이, 추가개발 용이, 독립적인 프로그래밍 가능

 

인터페이스 선언 기본

type 인터페이스명 interface {
	메소드1()	반환 값(타입 형)
	메소드2()	//반환 값 없을 경우
}

 

package main

import "fmt"

type test interface{} // 빈 인터페이스

func main() {
	var t test
	fmt.Println("ex : ", t)
}
ex :  <nil>

 

인터페이스 사용 기본

package main

import "fmt"

type Dog1 struct {
	name   string
	weight int
}

// Behavier1 인터페이스의 bite() 메소드를 Dog1구조체릐 리시버 메소드로 구현
func (d Dog1) bite() {
	fmt.Println(d.name, "bites!")
}

// 행동 인터페이스
type Behavier1 interface {
	bite()
}

func main() {

	dog1 := Dog1{"poll", 10}

	// 방법 1
	var inter1 Behavier1
	inter1 = dog1 // 인터페이스에 인스턴스 대입
	inter1.bite()

	// 방법 2
	dog2 := Dog1{"marry", 7}
	inter2 := Behavier1(dog2) // 많이쓰이는 방법
	inter2.bite()

	// 복수개 초기화 사용 방법
	// slice 타입 interface
	inters := []Behavier1{dog1, dog2}
	for _, i := range inters {
		fmt.Printf(" > ")
		i.bite()
	}

}

 

덕타이핑

  • 인터페이스에정의된 메소드 사용 유도
  • 코드의 가독성 및 유지보수 증가

 

  • 덕타이핑 : 구조체 및 변수의 값이나 타입은 상관하지 않고 오로지 구현된 메소드로만 판단하는 방식.
  • Go의 독보적이고 중요한 덕타이핑 특징 : 오리랑 같은 메소드(인터페이스)를 구현하여 사용할 수 있다면 다 오리다...!
  • A, B 구조체가 C인터페이스의 모든 메소드를 리시버메소드로 가지고 있다면, A,B는 C이다!! 가 성립.
    자동형변환 되어 C 인터페이스를 받는 모든 곳에 쓰일 수 있다.
package main

import "fmt"

// Dog, Cat 구조체 선언
type Dog2 struct {
	name   string
	weight int
}

type Cat struct {
	name   string
	weight int
}

// Dog 리시버메소드 선언 (Behavier2 인터페이스 implement)
func (d Dog2) bite2() {
	fmt.Println(d.name, "Dog bites!")
}

func (d Dog2) sounds() {
	fmt.Println(d.name, "Dog barks!")
}

func (d Dog2) run() {
	fmt.Println(d.name, "Dog is running!")
}

// Cat 리시버메소드 선언 (Behavier2 인터페이스 implement)
func (d Cat) bite2() {
	fmt.Println(d.name, "Cat 할퀴다!")
}
func (d Cat) sounds() {
	fmt.Println(d.name, "Cat cries!")
}

func (d Cat) run() {
	fmt.Println(d.name, "Cat is running!")
}

// 행동 인터페이스
type Behavier2 interface {
	bite2()
	sounds()
	run()
}

// 인터페이스 규격화
// 인터페이스를 파라미터로 받는 형식
func act(animal Behavier2) {
	animal.bite2()
	animal.sounds()
	animal.run()
}

func main() {

	dog := Dog2{"poll", 5}
	cat := Cat{"bob", 8}

// Behavier2 메소드를 전부 가지고 있기 때문에 
// 바로 형변환이 이루어지고 act의 매개변수로 넣을 수 있는 것이다.
	act(dog)
	act(cat)

}

 

인터페이스 익명 선언

  • 메소드의 매개변수를 받아 바로 인터페이스를 생성하는 방식. 
  • 매개변수가 들어오면 인터페이스 내의 메소드가 있는지 체크하고 내부 로직 실행시킴.
type Dog3 struct {
	name   string
	weight int
}

func (d Dog3) run2() {
	fmt.Println(d.name, "Dog is running!")
}

// 행동 인터페이스
type Behavier3 interface {
	run2()
}

// 인터페이스 익명 선언.
func act2(animal interface{ run2() }) {
	animal.run2()
}

func main() {
	dog := Dog3{"bob", 3}
	act2(dog)
}

 

빈 인터페이스 (만능 매개변수)

  • 함수내에서 어떠한 타입이라도 유연하게 매개변수로 받을 수 있다. (만능) -> 모든 타입 지정 가능
type Dog4 struct {
	name   string
	weight int
}

type Cat3 struct {
	name   string
	weight int
}

// interface{} 는 어떠한 타입이라도 매개변수로 받을 수 있어서 많이 씀.
func printValue(s interface{}) {
	fmt.Println("ex1 : ", s)
}

func main() {

	dog := Dog4{"poll", 100}
	cat := Cat3{"bob", 5}

	printValue(dog)
	printValue(cat)
	printValue(15)
	printValue("Animal")
	printValue(10.2)
	printValue([]Dog4{})
	printValue([5]Cat3{})

}