일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- struct
- UpstageAILab
- array
- golang pointer
- 메서드
- 상수
- package
- method
- 변수
- Pointer
- slice
- 스코프
- 패스트캠퍼스
- golang array
- scope
- golang slice remove
- 타입
- 업스테이지패스트캠퍼스
- golang interface
- receiver
- keyword
- Interface
- 패스트캠퍼스업스테이지에이아이랩
- golang slice
- 국비지원
- receiver method
- 패스트캠퍼스AI부트캠프
- 패스트캠퍼스업스테이지부트캠프
- 함수
- golang
- Today
- Total
느리지만 꾸준히, 코딩
Golang 캡슐화, 임베딩 본문
개요
Go 언어는 간결하고 효율적인 설계를 중시하며, 객체 지향 프로그래밍 패러다임을 직접적으로 지원하지 않습니다. 그러나 캡슐화(encapsulation)와 임베딩(embedding) 같은 개념을 통해 객체 지향 프로그래밍의 핵심 개념들을 구현할 수 있습니다.
1. 캡슐화 (Encapsulation)
캡슐화는 객체의 데이터를 외부로부터 숨기고, 그 데이터에 접근하거나 조작하는 방법을 제공하는 개념입니다. Go에서는 캡슐화를 구조체와 메서드를 통해 구현할 수 있습니다.
1.1 접근 제어
Golang에서는 대소문자를 사용하여 접근 제어를 수행합니다:
- 대문자로 시작하는 필드나 메서드: 외부에서 접근 가능 (public)
- 소문자로 시작하는 필드나 메서드: 같은 패키지 내에서만 접근 가능 (private)
1.2 구조체 (Struct)
Go에서는 struct를 사용하여 데이터를 캡슐화합니다. 구조체는 관련된 데이터를 그룹화하여 하나의 단위로 만들 수 있게 해줍니다.
// 생략...
type Person struct {
Name string // 외부에서 접근 가능
age int // 같은 패키지 내에서만 접근 가능
}
func (p *Person) SetAge(age int) {
if age > 0 {
p.age = age
}
}
func (p Person) GetAge() int {
return p.age
}
func main() {
person := Person{Name: "Alice"}
person.SetAge(30)
fmt.Printf("%s is %d years old\n", person.Name, person.GetAge())
}
이 예제에서 age 필드는 private이므로 직접 접근할 수 없고, SetAge와 GetAge 메서드를 통해서만 접근 및 수정이 가능합니다.
1.3 완전한 캡슐화
앞서 설명한 예제에서 Name 필드가 public으로 선언되어 있어 외부에서 직접 접근 및 수정이 가능했습니다. 이는 완전한 캡슐화를 위반하는 것으로, 데이터의 무결성을 해칠 수 있는 잠재적 위험이 있습니다.
문제점
type Person struct {
Name string // 외부에서 접근 가능
age int // 같은 패키지 내에서만 접근 가능
}
func main() {
person := Person{Name: "Alice"}
person.Name = "" // 유효하지 않은 이름으로 직접 수정 가능
}
이 코드에서 Name 필드는 외부에서 직접 수정이 가능하므로, 빈 문자열이나 유효하지 않은 이름으로 설정될 수 있습니다.
3.2 캡슐화 개선
더 나은 캡슐화를 위해 모든 필드를 private으로 만들고, getter와 setter 메서드를 통해 접근하도록 개선할 수 있습니다.
type Person struct {
name string
age int
}
func NewPerson(name string) Person {
return Person{name: name}
}
func (p *Person) SetName(name string) error {
if name == "" {
return errors.New("name cannot be empty")
}
p.name = name
return nil
}
func (p Person) GetName() string {
return p.name
}
func (p *Person) SetAge(age int) error {
if age < 0 {
return errors.New("age cannot be negative")
}
p.age = age
return nil
}
func (p Person) GetAge() int {
return p.age
}
func main() {
person := NewPerson("Alice")
err := person.SetName("")
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println("Name:", person.GetName())
}
캡슐화 정리
- 데이터 무결성: 유효하지 않은 데이터가 설정되는 것을 방지합니다.
- 유연성: 내부 구현을 변경하더라도 외부 인터페이스는 그대로 유지할 수 있습니다.
- 디버깅 용이성: 데이터 변경 지점을 명확히 알 수 있어 디버깅이 쉬워집니다.
2. 임베딩 (Embedding)
Golang Embedding(임베딩)은 다른 구조체를 현재의 구조체 내에 포함시키는 것을 의미합니다. 임베딩된 구조체는 필드와 메서드를 현재 구조체에서 직접 사용할 수 있으며, 이는 마치 상속처럼 동작하지만, Go에서는 명시적인 상속 개념이 없기 때문에 임베딩으로 이 기능을 구현합니다.
2.1 기본 임베딩
type Address struct {
Street string
City string
Country string
}
type Employee struct {
Name string
Address // 임베딩된 구조체
}
func main() {
emp := Employee{
Name: "Bob",
Address: Address{
Street: "123 Main St",
City: "Anytown",
Country: "USA",
},
}
fmt.Println(emp.Name) // 직접 접근
fmt.Println(emp.Street) // 임베딩된 필드에 직접 접근
}
이 예제에서 Employee 구조체는 Address 구조체를 임베딩하고 있습니다. 이를 통해 Employee의 인스턴스에서 Address의 필드에 직접 접근할 수 있습니다.
2.2 메서드 임베딩
임베딩된 구조체의 메서드도 외부 구조체에서 사용할 수 있습니다.
type Printer struct{}
func (p Printer) Print() {
fmt.Println("Printing...")
}
type Scanner struct{}
func (s Scanner) Scan() {
fmt.Println("Scanning...")
}
type PrinterScanner struct {
Printer
Scanner
}
func main() {
ps := PrinterScanner{}
ps.Print() // Printer의 메서드 호출
ps.Scan() // Scanner의 메서드 호출
}
이 예제에서 PrinterScanner 구조체는 Printer와 Scanner를 임베딩하여 두 구조체의 메서드를 모두 사용할 수 있습니다.
2.3 주의할 점
필드 충돌
임베딩된 구조체와 임베딩을 받는 구조체가 동일한 이름의 필드를 가지는 경우, 필드 충돌이 발생할 수 있습니다. 이 경우, Go는 가장 바깥 구조체의 필드를 우선적으로 사용합니다. 필요한 경우, 명시적으로 필드명을 지정해야 합니다.
type Address struct {
City string
}
type Person struct {
City string
Address
}
func main() {
p := Person{City: "Los Angeles", Address: Address{City: "San Francisco"}}
fmt.Println(p.City) // Los Angeles 출력
fmt.Println(p.Address.City) // San Francisco 출력
}
'프로그래밍 > Golang' 카테고리의 다른 글
Golang Date(날짜, 시간) 계산, 포맷팅 (0) | 2024.09.10 |
---|---|
Golang 함수 []any(슬라이스 파라미터) 와 ...any(가변인자) (0) | 2024.08.08 |
Golang Error 인터페이스 (0) | 2024.08.07 |
Golang에서 문자열 자르기 (0) | 2024.08.07 |
Golang 정수 타입과 아키텍처 의존성 (0) | 2024.08.06 |