학습
Go 객체지향 프로그래밍 (OOP)
Go 객체지향 프로그래밍 (OOP) — 중급
객체지향 프로그래밍 (OOP)
1. 도입 (왜 배워야 하는가)
객체지향 프로그래밍(OOP)은 소프트웨어 개발에서 매우 중요한 개념입니다. 실무에서 OOP를 활용하면 코드의 재사용성, 유지보수성, 확장성을 크게 향상시킬 수 있습니다. 예를 들어, 대규모 애플리케이션을 개발할 때 OOP를 사용하면 서로 다른 기능을 가진 모듈들을 독립적으로 개발하고, 나중에 통합하기가 수월해집니다.
반대로 OOP를 모르면 코드가 복잡해지고, 중복 코드가 발생할 확률이 높아지며, 유지보수가 어려워집니다. 이는 프로젝트의 전체 비용을 증가시키고, 개발 기간을 늘리는 원인이 됩니다.
2. 핵심 개념 설명
OOP의 핵심 개념은 다음과 같습니다:
- 클래스(Class): 객체의 설계도입니다. 클래스는 객체의 속성과 메서드를 정의합니다.
- 객체(Object): 클래스의 인스턴스입니다. 실제로 메모리에 할당된 데이터입니다.
- 상속(Inheritance): 한 클래스가 다른 클래스의 속성과 메서드를 물려받는 것입니다.
- 다형성(Polymorphism): 같은 이름의 메서드가 서로 다른 동작을 하는 것입니다.
이 개념들을 실생활 예시로 설명하자면, 자동차가 있습니다. '자동차'라는 클래스가 있고, 다양한 자동차 모델(예: 현대 아반떼, 기아 K5)이 객체로 존재합니다. 자동차라는 클래스는 속성(색상, 모델)과 메서드(주행, 정지)를 정의하고, 각 자동차 객체는 이 속성과 메서드를 가지고 있습니다.
| 용어 | 설명 |
|---|---|
| 클래스 | 객체의 설계도 |
| 객체 | 클래스의 인스턴스 |
| 상속 | 한 클래스가 다른 클래스의 속성과 메서드를 물려받는 것 |
| 다형성 | 같은 이름의 메서드가 서로 다른 동작을 하는 것 |
3. 기본 코드 예제
아래는 Go 언어로 클래스와 객체를 정의하는 간단한 예제입니다.
package main
import "fmt"
// Car 클래스 정의
type Car struct {
Color string
Model string
}
// Car의 메서드
func (c Car) Drive() {
fmt.Printf("%s %s가 주행합니다.\n", c.Color, c.Model)
}
func main() {
// Car 객체 생성
myCar := Car{Color: "빨간색", Model: "현대 아반떼"}
// 메서드 호출
myCar.Drive()
}
실행 결과:
빨간색 현대 아반떼가 주행합니다.
동작 설명:
Car라는 구조체를 정의합니다. 이 구조체는Color와Model이라는 두 개의 속성을 가집니다.Drive라는 메서드를 정의하여 자동차가 주행할 때 출력할 내용을 설정합니다.main함수에서Car객체를 생성하고,Drive메서드를 호출하여 자동차가 주행하는 메시지를 출력합니다.- OOP는 소프트웨어 개발에서 코드의 재사용성과 유지보수성을 높인다.
- 클래스와 객체, 상속과 다형성은 OOP의 핵심 개념이다.
- 실전에서 OOP는 장바구니, 도서관 시스템 등 다양한 분야에서 활용된다.
- 포인터 수신자의 사용과 전역변수의 관리에 주의해야 한다.
4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니를 구현할 때
장바구니 기능을 구현할 때, Cart라는 클래스를 만들고, Item이라는 클래스를 정의하여 장바구니에 담길 각 아이템의 속성을 관리할 수 있습니다.
package main
import "fmt"
type Item struct {
Name string
Price float64
}
type Cart struct {
Items []Item
}
// Cart에 아이템 추가
func (c *Cart) AddItem(item Item) {
c.Items = append(c.Items, item)
}
// 장바구니 총액 계산
func (c Cart) Total() float64 {
total := 0.0
for _, item := range c.Items {
total += item.Price
}
return total
}
func main() {
cart := Cart{}
cart.AddItem(Item{Name: "스마트폰", Price: 500000})
cart.AddItem(Item{Name: "태블릿", Price: 300000})
fmt.Printf("총액: %.2f원\n", cart.Total())
}
실행 결과:
총액: 800000.00원
예제 2: 도서관 시스템 구현하기
도서관 시스템에서 Book 클래스와 Library 클래스를 정의하여 도서를 관리할 수 있습니다.
package main
import "fmt"
type Book struct {
Title string
Author string
}
type Library struct {
Books []Book
}
// 도서 추가
func (lib *Library) AddBook(book Book) {
lib.Books = append(lib.Books, book)
}
// 도서 목록 출력
func (lib Library) ListBooks() {
for _, book := range lib.Books {
fmt.Printf("제목: %s, 저자: %s\n", book.Title, book.Author)
}
}
func main() {
library := Library{}
library.AddBook(Book{Title: "Go 프로그래밍", Author: "저자1"})
library.AddBook(Book{Title: "OOP 기초", Author: "저자2"})
library.ListBooks()
}
실행 결과:
제목: Go 프로그래밍, 저자: 저자1
제목: OOP 기초, 저자: 저자2
5. 흔한 실수와 주의사항
실수 1: 메서드에서 포인터 수신자 사용을 잊음
잘못된 코드:
func (c Car) Drive() { ... } // 값 수신자
올바른 코드:
func (c *Car) Drive() { ... } // 포인터 수신자
메서드에서 객체의 속성을 수정할 때는 포인터 수신자를 사용해야 합니다.
실수 2: 객체를 전역변수로 선언
잘못된 코드:
var myCar Car // 전역변수
올바른 코드:
func main() {
myCar := Car{Color: "파란색", Model: "기아 K5"} // 지역변수
}
전역변수는 코드의 예측 가능성을 낮추고, 유지보수를 어렵게 만듭니다.
6. 정리
다음에 학습하면 좋은 주제: Go의 인터페이스, 고루틴 및 채널, 디자인 패턴.