티스토리 뷰
📺 시리즈
2023.10.02 - [Go/디자인 패턴] - [Go] SOLID in Go - SOLID란?
2023.10.03 - [Go/디자인 패턴] - [Go] SOLID in Go - 구조체와 메서드
2023.10.04 - [Go/디자인 패턴] - [Go] SOLID in Go - 인터페이스
2023.10.09 - [Go/디자인 패턴] - [Go] SOLID in Go - 컴포지션
🎁 패키지
Go의 패키지는 다른 프로그래밍 언어에서의 라이브러리나 모듈의 개념으로, '.go' 접미사를 가진 연관된 코드들을 디렉터리 단위로 모아 코드의 재사용성을 높이는 중요한 개념입니다.
패키지 선언
파일의 맨 위에 'package' 키워드를 사용하여 패키지를 선언합니다. 예를 들어, 'package main'은 메인 프로그램의 진입점을 나타내는 패키지입니다.
package main
패키지 임포트
다른 패키지에 있는 변수, 함수 또는 타입을 사용하려면 'import' 키워드를 사용하여 해당 패키지를 가져와야 합니다.
import "fmt"
캡슐화(Encapsulation)
Go에는 다른 객체지향 언어에서 제공하는 public, private과 같은 명시적인 접근 제어자가 존재하지 않습니다. 대신 Go는 패키지 수준에서 패키지를 구성하는 각 요소의 이름이 대문자 또는 소문자로 시작하는지에 따라 접근을 제한함으로써 캡슐화를 제공합니다.
요소의 이름이 대문자로 시작하는 경우, 이는 흔히 말하는 'public' 접근 제어자를 사용한 것과 마찬가지이며 패키지 외부로 노출(exported)됩니다. 반면, 요소의 이름이 소문자로 시작하면 'private' 접근 제어자를 사용한 것과 마찬가지이므로 패키지 외부로 노출되지 않(unexported)습니다. 이름이 소문자로 시작하는 원소들은 패키지 외부로 노출되지 않을 뿐이지, 패키지 내부에서는 사용이 가능합니다. Go는 이런 식으로 패키지 외부에서 소문자로 시작하는 요소들에 대한 접근을 제한함으로써 캡슐화를 구현합니다.
package gopher
import (
"fmt"
"sync"
"time"
)
type gopherState int // 소문자로 시작하는 타입은 외부로 노출되지 않는다.
const (
awake gopherState = iota // 소문자로 시작하는 상수는 외부로 노출되지 않는다.
sleeping
eating
)
type Gopher struct { // 대문자로 시작하는 타입은 외부로 노출된다.
Name string // 대문자로 시작하는 필드는 외부로 노출된다.
state gopherState // 소문자로 시작하는 필드는 외부로 노출되지 않는다.
mu sync.Mutex
}
func New(name string) *Gopher { // 대문자로 시작하는 함수는 외부로 노출된다.
return &Gopher{
Name: name,
state: awake,
mu: sync.Mutex{},
}
}
func (g *Gopher) Sleep(t time.Duration) { // 대문자로 시작하는 메서드는 외부로 노출된다.
g.sleep(t) //
}
func (g *Gopher) sleep(t time.Duration) { // 소문자로 시작하는 메서드는 외부로 노출되지 않는다.
fmt.Printf("%s is sleeping for %s\n", g.Name, t)
g.mu.Lock()
g.state = sleeping // 소문자로 시작하는 원소는 외부로는 노출되지 않지만, 같은 패키지 내에서는 사용할 수 있다.
g.mu.Unlock()
time.Sleep(t)
g.mu.Lock()
defer g.mu.Unlock()
fmt.Printf("%s is awake\n", g.Name)
g.state = awake
}
func (g *Gopher) Eat(something string) {
fmt.Printf("%s is eating %s!\n", g.Name, something)
}
package main
import (
"example/gopher"
"time"
)
func main() {
g := gopher.New("Gorgeous Gopher")
g.Eat("pizza")
g.Sleep(5 * time.Second)
// g.sleep(5 * time.Second) // this is not allowed because sleep is not exported
}
$ go run main.go
Gorgeous Gopher is eating pizza!
Gorgeous Gopher is sleeping for 5s
Gorgeous Gopher is awake
마지막 주석을 제거하고 실행할 경우
$ go run main.go
# command-line-arguments
./main.go:13:4: g.sleep undefined (type *gopher.Gopher has no field or method sleep, but does have Sleep)
🙏 마치며
Go에서 패키지를 통해 캡슐화를 구현하는 방법에 대해 간단하게 살펴봤습니다. 지금까지 Go에서 제공하는 기능들과 객체지향 프로그래밍 키워드들을 매핑하면 다음과 같습니다.
- 구조체와 메서드 - 객체
- 인터페이스 - 다형성, 추상화
- 컴포지션 - 상속
- 캡슐화 - 패키지
개인적으로는 프로그래밍 언어를 Go를 통해 제대로 접했다보니, 객체지향 언어에 익숙하지 않아서 억지로 끼워 맞춘 듯한 느낌도 있긴 합니다. 관련 커뮤니티에서도 Go가 객체지향인지에 대한 질문이 주기적으로 올라오는 것 같네요. 그런데 Go가 태생적으로 클래스와 상속을 지원하지 않는 그런 아이인 것을 어떻게 합니까? 그로 인해 class, extends, implements, abstract, public, private, internal, override 등등의 키워드가 Go에서는 사용되지 않는다는 것. 그런 간결함이 가지는 매력이 참 좋은 것 같습니다.
다음 게시글에서는 본격적으로 SOLID 원칙의 가장 앞글자, 단일 책임 원칙에 대해 알아보겠습니다.
📖 참고자료
글에서 수정이 필요한 부분이나 설명이 부족한 부분이 있다면 댓글로 남겨주세요!
'Go > 디자인 패턴' 카테고리의 다른 글
[Go] SOLID in Go - 개방 폐쇄 원칙 (0) | 2023.10.12 |
---|---|
[Go] SOLID in Go - 단일 책임 원칙 (1) | 2023.10.11 |
[Go] SOLID in Go - 컴포지션 (1) | 2023.10.09 |
[Go] SOLID in Go - 인터페이스 (1) | 2023.10.04 |
[Go] SOLID in Go - 구조체와 메서드 (0) | 2023.10.03 |