Go 기초 11. OOP, Interface

Object Oriented Programming

객체 지향 중심 프로그래밍

OOP는 추상적인 개념이 아닌 프로그래밍을 잘 하기 위한 기술이다.

OOP이전의 프로그래밍은 순서를 중요시 하는 절차 지향 프로그래밍이다.

ex) strawberry sandwitch

package main

import "fmt"

type Bread struct {
	val string
}

type StrawberryJam struct {
	opened bool
}

type SpoonOfStrawberry struct {
}

type Sandwitch struct {
	val string
}

func GetBreads(num int) []*Bread {
	breads := make([]*Bread, num)
	for i := 0; i < num; i++ {
		breads[i] = &Bread{val: "bread"}
	}
	return breads
}

func OpenStrawberryJam(jam *StrawberryJam) {
	jam.opened = true
}

func GetOneSpoon(_ *StrawberryJam) *SpoonOfStrawberry {
	return &SpoonOfStrawberry{}
}

func PutJamOnBread(bread *Bread, jam *SpoonOfStrawberry) {
	bread.val += " + Strawberry Jam"
}

func MakeSandwitch(breads []*Bread) *Sandwitch {
	sandwitch := &Sandwitch{}
	for i := 0; i < len(breads); i++ {
		sandwitch.val += breads[i].val + " + "
	}
	return sandwitch
}

func main() {
	// 1. 빵 두개를 꺼낸다.
	breads := GetBreads(2)

	jam := &StrawberryJam{}

	// 2. 딸기잼 뚜껑을 연다.
	OpenStrawberryJam(jam)

	// 3. 딸기잼을 한스푼 뜬다.
	spoon := GetOneSpoon(jam)

	// 4. 딸기잼을 빵에 바른다.
	PutJamOnBread(breads[0], spoon)

	// 5. 빵을 덮는다.
	sandwitch := MakeSandwitch(breads)

	// 6. 완성
	fmt.Println(sandwitch.val)
}
-----------------------------------
bread + Strawberry Jam + bread +

이상태에서 딸기잼이 아닌 오렌지잼으로 바꾸다고 했을때.


ex) orangejam sandwitch

package main

import "fmt"

type Bread struct {
	val string
}

type StrawberryJam struct {
	opened bool
}

type SpoonOfStrawberry struct {
}

type SpoonOfOrangeJam struct {
} //새로운 구조체 추가

type Sandwitch struct {
	val string
}

type OrangeJam struct {
	opened bool
} // 오렌지 잼 추가

func GetBreads(num int) []*Bread {
	breads := make([]*Bread, num)
	for i := 0; i < num; i++ {
		breads[i] = &Bread{val: "bread"}
	}
	return breads
}

func OpenStrawberryJam(jam *StrawberryJam) {
	jam.opened = true
}

func OpenOrangeJam(jam *OrangeJam) {
	jam.opened = true
} //오렌지 잼을 추가 했기 때문에 새로운 함수 추가

func GetOneSpoon(_ *StrawberryJam) *SpoonOfStrawberry {
	return &SpoonOfStrawberry{}
}

func GetOneOrangeJamSpoon(_ *OrangeJam) *SpoonOfOrangeJam {
	return &SpoonOfOrangeJam{}
} //새로운 함수 추가

func PutJamOnBread(bread *Bread, jam *SpoonOfStrawberry) {
	bread.val += " + Strawberry Jam"
}

func PutOrangeJamOnBread(bread *Bread, jam *SpoonOfOrangeJam) {
	bread.val += " + Orange Jam"
} //새로운 함수 추가

func MakeSandwitch(breads []*Bread) *Sandwitch {
	sandwitch := &Sandwitch{}
	for i := 0; i < len(breads); i++ {
		sandwitch.val += breads[i].val + " + "
	}
	return sandwitch
}

func main() {
	// 1. 빵 두개를 꺼낸다.
	breads := GetBreads(2)

	//jam := &StrawberryJam{}
	jam := &OrangeJam{}

	// 2.  오렌지잼 뚜껑을 연다.
	//OpenStrawberryJam(jam)
	OpenOrangeJam(jam)

	// 3. 오렌지잼을 한스푼 뜬다.
	//spoon := GetOneSpoon(jam)
	spoon := GetOneOrangeJamSpoon(jam)

	// 4.  오렌지잼을 빵에 바른다.
	//PutJamOnBread(breads[0], spoon)
	PutOrangeJamOnBread(breads[0], spoon)

	// 5. 빵을 덮는다.
	sandwitch := MakeSandwitch(breads)

	// 6. 완성
	fmt.Println(sandwitch.val)
}
------------------------------------
bread + Orange Jam + bread + 

딸기잼을 오렌지잼으로 바꾸었을 뿐인데 8군데가 수정 된것을 알 수 있다.

이것이 현업에서는 수정할때 그 범위가 엄청나게 커서 유지, 보수가 힘들다.

이런것들을 해결하기 위해 OOP라는 기술이 나왔다.
하지만 OOP가 절대적인 해결책은 아니므로 프로그램을 잘 짜는게 제일 중요하다.


object란?

상태 + 기능
상태 = 메모리 상태
기능 = 어떻게
상태를 어떻게 바꿀 것인가?

variable + function = object

package main

import "fmt"

type Bread struct {
	val string
}

type Jam struct {
}

func (b *Bread) PutJam(jam *Jam) {
	b.val += jam.GetVal()
} // bread의 매소드로 bread에 jam을 바름

func (b *Bread) String() string {
	return b.val
} // 만약 string이 있을 경우

func (j *Jam) GetVal() string {
	return "+ jam"
} // jam의 매소드로 잼을 바름

func main() {
	bread := &Bread{val: "bread"}
	jam := &Jam{}
	//bread 인스턴스와 jam의 인스턴스를 만든다.

	bread.PutJam(jam)
	//bread 인스턴스에 속해있는 PutJam을 호출

	fmt.Println(bread)
}
--------------------------------------
bread+ jam

위의 프로그램의 객체를 잼, 빵 이라고 한다면
이 잼과 빵이 각자 기능을 가지고 오브젝트를 형성하고 각 각의 오브젝트간에 커뮤니케이션하는 관계를 성립함으로써 프로그램을 완성시킨다.


Interface

객체간의 상호 관계를 정의한 것

객체(object)는 기능(method)를 가지는데 이 기능에는 내부 기능과 외부 기능이 있다. 내부 기능은 내부에서만 호출이 되고, 외부 기능은 외부에서 호출 되어진다. 이 때 외부와 서로 관계를 맺고있는 외부 기능을 interface라고 한다.

interface는 객체와 관계를 유지한 상태로 때어내서 종속성을 끊어내고 독립 시키게 되면 확장을 하는데 용이하다.

interface 선언 방법

type 인터페이스명 interface {
메소드명 타입
메소드명 타입
}

ex)

package main

import (
	"fmt"
	"strconv"
)

type InterfaceA interface {
	AAA(int) int
	BBB(int) string
}

type StructA struct {
}

func (a *StructA) AAA(x int) int {
	return x * x
}

func (a *StructA) BBB(x int) string {
	return "X=" + strconv.Itoa(x)
}

func main() {
	var c InterfaceA //inteface 타입 c
	c = &StructA{} 
	// c가 StructA의 주소값을 가짐
	// StructA는 AAA와 BBB의 메소드를 가지고 있음

	fmt.Println(c.BBB(3))

}
-------------------------------------
X=3

좋은 웹페이지 즐겨찾기