Go 언어에서의 디자인 패턴 모범 사례
Ethan Miller
Product Engineer · Leapcell

Go 언어로 구현된 10가지 디자인 패턴 및 인터넷 시나리오에서의 적용
1. 싱글톤 패턴
패턴 정의
전역적으로 클래스의 인스턴스가 하나만 생성되도록 보장하고, 통일된 접근 지점을 제공합니다. 생성 패턴에 속하며, 전역적인 고유 제어가 필요한 시나리오에 적합합니다.
핵심 특징
- 고유 인스턴스: 전역적으로 유일한 객체 인스턴스가 존재합니다.
- 자가 초기화: 클래스 자체가 인스턴스 생성을 책임집니다.
- 전역 접근: 정적 메서드 또는 전역 변수를 통해 접근 진입점을 제공합니다.
장단점
| 장점 | 단점 |
|---|---|
| 리소스/상태의 전역적 고유성 보장 | 높은 응집도 원칙 위반, 높은 모듈 결합도 |
| 리소스의 반복적인 생성을 줄임 | 단위 테스트 격리가 어려움 |
| 편리한 전역 접근 지점 제공 | 의존성 주입 패턴을 손상시킴 |
시나리오 애플리케이션
- 마이크로서비스 설정 센터 (Spring Cloud Config의 대안): 분산 시스템의 설정을 균일하게 관리합니다.
- 데이터베이스 연결 풀 (PostgreSQL/MySQL의 연결 관리): 동시 연결 수를 제어합니다.
- 분산 로그 서비스 (ELK 스택의 로그 수집기): 로그 핸들러의 반복적인 생성을 방지합니다.
- API 속도 제한기 (Stripe API의 요청 빈도 제어): 속도 제한 상태를 전역적으로 공유합니다.
Go 언어 구현 (동시성 안전 버전)
package singleton import ( "sync" ) // ConfigManager 싱글톤 구조체, 설정 관리 시뮬레이션 type ConfigManager struct { AppConfig map[string]string } var ( once sync.Once instance *ConfigManager ) // GetInstance 전역 접근 지점, sync.Once를 사용하여 동시성 안전 보장 func GetInstance() *ConfigManager { once.Do(func() { instance = &ConfigManager{ AppConfig: map[string]string{ "env": "prod", "port": "8080", "timeout": "30s", }, } }) return instance } // 동시성 테스트 예제 func TestConcurrency() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() config := GetInstance() println(config.AppConfig["env"]) }() } wg.Wait() }
2. 팩토리 패턴
패턴 정의
객체 생성 로직을 캡슐화하고, 서브클래스를 통해 특정 제품의 인스턴스를 결정합니다. 생성 패턴에 속하며, 객체 생성을 사용과 분리합니다.
핵심 특징
- 생성 로직 캡슐화: 클라이언트는 구체적인 생성 세부 정보를 알 필요가 없습니다.
- 다형성 지원: 인터페이스를 통해 제품군을 확장합니다.
- 개방-폐쇄 원칙: 기존 코드를 수정하지 않고 새로운 제품을 추가할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 객체 생성을 사용과 분리 | 클래스 수 증가 (각 제품마다 해당 팩토리가 필요함) |
| 새로운 제품 확장 용이 | 팩토리 클래스가 너무 복잡해질 수 있음 |
| 의존성 역전 원칙 준수 | 클라이언트는 제품의 추상 인터페이스를 알아야 함 |
시나리오 애플리케이션
- 결제 게이트웨이 통합 (Stripe/PayPal/Apple Pay): 결제 방식에 따라 다른 처리기를 생성합니다.
- 클라우드 스토리지 클라이언트 (S3/GCS/Azure Blob): 스토리지 서비스에 따라 해당 API 클라이언트를 생성합니다.
- 메시지 큐 어댑터 (Kafka/RabbitMQ/NATS): 메시지 전송 인터페이스의 생성 로직을 통합합니다.
- 제3자 로그인 서비스 (OAuth2/OpenID Connect): 다른 플랫폼에 대한 인증 클라이언트를 동적으로 생성합니다.
Go 언어 구현 (추상 팩토리 패턴)
package factory import "fmt" // PaymentProcessor 결제 처리기 인터페이스 type PaymentProcessor interface { Process(amount float64) string } // StripeProcessor Stripe 결제 구현 type StripeProcessor struct{} func (s *StripeProcessor) Process(amount float64) string { return fmt.Sprintf("Stripe processed $%.2f", amount) } // PayPalProcessor PayPal 결제 구현 type PayPalProcessor struct{} func (p *PayPalProcessor) Process(amount float64) string { return fmt.Sprintf("PayPal processed $%.2f", amount) } // PaymentFactory 팩토리 인터페이스 type PaymentFactory interface { CreateProcessor() PaymentProcessor } // StripeFactory Stripe 팩토리 구현 type StripeFactory struct{} func (s *StripeFactory) CreateProcessor() PaymentProcessor { return &StripeProcessor{} } // PayPalFactory PayPal 팩토리 구현 type PayPalFactory struct{} func (p *PayPalFactory) CreateProcessor() PaymentProcessor { return &PayPalProcessor{} } // 클라이언트 사용 예제 func NewPaymentClient(factory PaymentFactory) PaymentProcessor { return factory.CreateProcessor() }
3. 옵저버 패턴
패턴 정의
객체 간에 일대다 의존 관계를 정의하고, 주체의 상태가 변경되면 모든 옵저버에게 자동으로 알립니다. 행동 패턴에 속하며, 이벤트 기반 시나리오에 적합합니다.
핵심 특징
- 이벤트 기반: 주체의 상태 변경이 옵저버의 업데이트를 트리거합니다.
- 느슨한 결합: 주체와 옵저버는 추상 인터페이스를 통해서만 상호 작용합니다.
- 동적 구독: 옵저버는 언제든지 등록하거나 등록 해제할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 브로드캐스트 스타일 이벤트 알림 지원 | 많은 수의 옵저버가 성능 문제를 야기할 수 있음 |
| 새로운 옵저버 유형 확장 용이 | 순환 종속성이 메모리 누수를 유발할 수 있음 |
| 개방-폐쇄 원칙 준수 | 주체는 옵저버 목록을 유지해야 함 |
시나리오 애플리케이션
- 실시간 알림 시스템 (Slack 채널 업데이트/Zoom 회의 알림): 사용자가 주체에 구독하여 실시간 알림을 받습니다.
- 주식 시세 플랫폼 (Robinhood/Nasdaq 실시간 시세): 투자자가 주식 코드를 구독하여 가격 변동을 얻습니다.
- 전자상거래 재고 모니터링 (Amazon 상품 재입고 알림): 사용자가 상품을 구독하여 재고 변경 알림을 받습니다.
- 분산 시스템 모니터링 (Datadog 메트릭 알람): 모니터링 서비스가 마이크로서비스의 상태 변경을 구독합니다.
Go 언어 구현 (이벤트 기반 모델)
package observer import "fmt" // Observer 옵저버 인터페이스 type Observer interface { Update(message string) } // Subject 주제 인터페이스 type Subject interface { Attach(observer Observer) Detach(observer Observer) Notify(message string) } // StockTicker 특정 주제: 주식 시세 type StockTicker struct { observers []Observer symbol string price float64 } func (s *StockTicker) Attach(observer Observer) { s.observers = append(s.observers, observer) } func (s *StockTicker) Detach(observer Observer) { for i, o := range s.observers { if o == observer { s.observers = append(s.observers[:i], s.observers[i+1:]...) return } } } func (s *StockTicker) Notify(message string) { for _, o := range s.observers { o.Update(message) } } // Investor 특정 옵저버: 투자자 type Investor struct { name string } func (i *Investor) Update(message string) { fmt.Printf("%s received: %s\n", i.name, message) }
4. 데코레이터 패턴
패턴 정의
객체에 새로운 기능을 동적으로 추가하고, 상속이 아닌 컴포지션을 통해 책임을 확장합니다. 구조 패턴에 속하며, 기능 계층화가 필요한 시나리오에 적합합니다.
핵심 특징
- 투명한 확장: 인터페이스를 일관되게 유지하고 클라이언트는 이를 알지 못합니다.
- 컴포지션 기능: 여러 계층의 데코레이터 중첩을 지원합니다.
- 런타임 바인딩: 객체 기능의 조합을 동적으로 결정합니다.
장단점
| 장점 | 단점 |
|---|---|
| 상속 계층 폭발 방지 | 다층 데코레이터의 디버깅이 어려울 수 있음 |
| 기능의 자유로운 조합 지원 | 과도한 사용은 시스템 복잡도를 증가시킬 수 있음 |
| 개방-폐쇄 원칙 준수 | 장식 순서가 실행 결과에 영향을 미칠 수 있음 |
시나리오 애플리케이션
- API 미들웨어 (Express.js/Koa.js 미들웨어 시스템): 로깅, 인증, 속도 제한과 같은 함수를 쌓습니다.
- 전자상거래 주문 처리 (배송비 계산/할인 제공/세금 처리): 총 주문 금액을 단계별로 계산합니다.
- 클라우드 스토리지 서비스 (S3 암호화/압축/CDN 가속): 스토리지 기능을 동적으로 조합합니다.
- 마이크로서비스 게이트웨이 (Kong/NginX 플러그인 시스템): 요청 검증, 응답 변환, 트래픽 모니터링.
Go 언어 구현 (HTTP 미들웨어 시뮬레이션)
package decorator import "fmt" // Handler 기본 처리 함수 type Handler func(request string) string // LogDecorator 로깅 데코레이터 func LogDecorator(next Handler) Handler { return func(request string) string { fmt.Printf("Received request: %s\n", request) return next(request) } } // AuthDecorator 인증 데코레이터 func AuthDecorator(next Handler) Handler { return func(request string) string { if request != "authenticated" { return "Unauthorized" } return next(request) } } // 기본 처리 함수 func BasicHandler(request string) string { return fmt.Sprintf("Processed: %s", request) } // 복합 데코레이터 예제 func CompositeHandler() Handler { return LogDecorator(AuthDecorator(BasicHandler)) }
5. 전략 패턴
패턴 정의
알고리즘을 독립적인 전략 클래스로 캡슐화하고, 런타임에 동적 전환을 지원합니다. 행동 패턴에 속하며, 여러 알고리즘이 있는 시나리오에 적합합니다.
핵심 특징
- 알고리즘 캡슐화: 각 전략은 알고리즘을 독립적으로 구현합니다.
- 전략 전환: 런타임에 동적으로 전략을 선택합니다.
- 개방-폐쇄 원칙: 기존 코드를 수정하지 않고 새로운 전략을 추가할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 알고리즘을 클라이언트와 분리 | 클라이언트는 모든 전략 유형을 알아야 함 |
| 알고리즘 확장 및 교체 용이 | 전략 클래스 수가 급증할 수 있음 |
| 복합 전략 지원 | 전략 간 상태 공유가 어려움 |
시나리오 애플리케이션
- 전자상거래 프로모션 엔진 (전체 할인/부분 할인/사은품 전략): 활동 유형에 따라 계산 로직을 동적으로 전환합니다.
- 물류 배송 시스템 (FedEx/UPS/USPS 배송 전략): 사용자의 선택에 따라 배송비를 계산합니다.
- 데이터 정렬 서비스 (가격/판매량/평점별 정렬): 프론트엔드 요청이 정렬 전략을 결정합니다.
- 광고 배치 알고리즘 (정밀 마케팅/지역 타겟팅/빈도 제어): 배치 전략을 실시간으로 조정합니다.
Go 언어 구현 (전자상거래 프로모션 계산)
package strategy import "fmt" // PromotionStrategy 프로모션 전략 인터페이스 type PromotionStrategy interface { Calculate(amount float64) float64 } // PercentDiscount 백분율 할인 전략 type PercentDiscount struct { rate float64 // 할인율 (0.1 = 10%) } func (p *PercentDiscount) Calculate(amount float64) float64 { return amount * (1 - p.rate) } // FixedDiscount 고정 금액 할인 전략 type FixedDiscount struct { offset float64 // 고정 금액 할인 } func (f *FixedDiscount) Calculate(amount float64) float64 { if amount > f.offset { return amount - f.offset } return amount } // CheckoutContext 계산 컨텍스트 type CheckoutContext struct { strategy PromotionStrategy } func (c *CheckoutContext) SetStrategy(strategy PromotionStrategy) { c.strategy = strategy } func (c *CheckoutContext) CalculateFinalAmount(amount float64) float64 { return c.strategy.Calculate(amount) }
6. 어댑터 패턴
패턴 정의
호환되지 않는 인터페이스를 변환하여 다른 인터페이스를 가진 클래스들이 함께 작동하도록 합니다. 구조 패턴에 속하며, 시스템 통합 시나리오에 적합합니다.
핵심 특징
- 인터페이스 변환: 소스 인터페이스를 대상 인터페이스에 맞게 조정합니다.
- 시스템 분리: 클라이언트와 어댑티는 직접 상호 작용할 필요가 없습니다.
- 호환성: 기존 시스템 코드를 유지하고 어댑터 계층을 추가합니다.
장단점
| 장점 | 단점 |
|---|---|
| 인터페이스 비호환성 문제 해결 | 시스템 추상화 계층 복잡성 증가 |
| 레거시 시스템 코드 재사용 | 과도한 사용은 시스템 유지보수를 어렵게 만들 수 있음 |
| 양방향 어댑터 지원 | 성능 오버헤드를 발생시킬 수 있음 |
시나리오 애플리케이션
- 레거시 시스템 마이그레이션 (COBOL 시스템을 마이크로서비스 아키텍처에 통합): 기존 시스템 API를 조정합니다.
- 제3자 라이브러리 통합 (MongoDB 드라이버를 SQL 인터페이스에 적용): 데이터 액세스 계층을 통합합니다.
- 크로스 플랫폼 개발 (iOS/Android 네이티브 API를 통일된 인터페이스에 적용): 모바일 애플리케이션 프레임워크.
- 클라우드 서비스 통합 (AWS SQS를 Kafka 메시지 형식에 적용): 하이브리드 클라우드 아키텍처.
Go 언어 구현 (제3자 결제 어댑테이션)
package adapter import ( "errors" "fmt" ) // ThirdPartyPayment 제3자 결제 인터페이스 (소스 인터페이스) type ThirdPartyPayment interface { ProcessPayment(orderID string, amount float64) error } // LegacyPayPal 레거시 PayPal 구현 (소스 구현) type LegacyPayPal struct{} func (p *LegacyPayPal) ProcessPayment(orderID string, amount float64) error { fmt.Printf("Legacy PayPal processing order %s for $%.2f\n", orderID, amount) return nil } // TargetPayment 대상 결제 인터페이스 (통합 인터페이스) type TargetPayment interface { Pay(orderID string, amountUSD float64) error } // PayPalAdapter 어댑터 구현 type PayPalAdapter struct { legacy *LegacyPayPal } func (a *PayPalAdapter) Pay(orderID string, amountUSD float64) error { // 대상 인터페이스를 소스 인터페이스 매개변수로 변환 return a.legacy.ProcessPayment(orderID, amountUSD) } // 호환되지 않는 상황 처리 예제 func HandleIncompatiblePayment(payment ThirdPartyPayment) TargetPayment { return &PayPalAdapter{legacy: payment.(*LegacyPayPal)} }
7. 프록시 패턴
패턴 정의
대상 객체에 대한 접근을 제어하기 위해 프록시 계층을 제공합니다. 구조 패턴에 속하며, 원격 접근 및 권한 제어와 같은 시나리오에 적합합니다.
핵심 특징
- 접근 제어: 프록시 계층이 요청을 가로채고 처리합니다.
- 지연 로딩: 필요할 때 대상 객체를 생성합니다.
- 책임 분리: 프록시는 비즈니스 로직이 아닌 것(로깅/보안/캐싱)을 처리합니다.
장단점
| 장점 | 단점 |
|---|---|
| 대상 객체 보호 | 요청 처리 지연 증가 |
| 분산 접근 지원 | 프록시 계층이 단일 실패 지점이 될 수 있음 |
| 지연 로딩 구현 | 프록시 클래스와 대상 클래스의 인터페이스가 일치해야 함 |
시나리오 애플리케이션
- API 게이트웨이 (Apigee/Postman API 관리): 백엔드 마이크로서비스를 프록시하고 통합 진입점을 제공합니다.
- 캐시 프록시 (Redis/Memcached 캐시 계층): 데이터베이스 쿼리 결과를 캐싱합니다.
- 권한 프록시 (OAuth2 인증 서버): 요청을 가로채 사용자 권한을 확인합니다.
- 원격 프록시 (gRPC 원격 서비스 호출): 네트워크 통신 세부 정보를 숨깁니다.
Go 언어 구현 (캐시 프록시)
package proxy import ( "sync" "time" ) // RealData 실제 데이터 객체 (데이터베이스 쿼리) type RealData struct { ID string Content string LastUpdate time.Time } func (r *RealData) FetchData() string { // 데이터베이스 쿼리 지연 시뮬레이션 time.Sleep(500 * time.Millisecond) return r.Content } // CacheProxy 캐시 프록시 type CacheProxy struct { realData *RealData cache map[string]string mu sync.Mutex } func NewCacheProxy(id string, content string) *CacheProxy { return &CacheProxy{ realData: &RealData{ID: id, Content: content, LastUpdate: time.Now()}, cache: make(map[string]string), } } func (c *CacheProxy) FetchData() string { c.mu.Lock() defer c.mu.Unlock() if data, exists := c.cache[c.realData.ID]; exists { return data // 캐시된 데이터 직접 반환 } // 첫 번째 접근, 실제 데이터 가져와서 캐싱 data := c.realData.FetchData() c.cache[c.realData.ID] = data return data }
8. 커맨드 패턴
패턴 정의
요청을 커맨드 객체로 캡슐화하여 요청 송신자와 수신자를 분리합니다. 행동 패턴에 속하며, 취소 및 로깅 지원이 필요한 시나리오에 적합합니다.
핵심 특징
- 요청 캡슐화: 커맨드 객체는 실행에 필요한 모든 정보를 포함합니다.
- 트랜잭션 지원: 일괄 실행 및 롤백을 지원합니다.
- 로깅: 커맨드의 실행 기록을 지속할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 실행 취소/다시 실행 작업 지원 | 커맨드 클래스 수가 크게 늘어날 수 있음 |
| 요청 송수신 분리 | 복잡한 커맨드 로직 유지보수가 어려움 |
| 일괄 처리 지원 | 커맨드 매개변수는 미리 결정되어야 함 |
시나리오 애플리케이션
- 버전 관리 시스템 (Git 커밋 작업): 각 커밋은 롤백을 지원하는 커맨드로 간주될 수 있습니다.
- 데이터베이스 트랜잭션 (ACID 작업 캡슐화): 여러 SQL 커맨드를 결합하여 커밋/롤백을 지원합니다.
- 작업 스케줄링 시스템 (Airflow 작업 오케스트레이션): 분산 작업을 실행 가능한 커맨드로 캡슐화합니다.
- 텍스트 편집기 (취소/다시 실행 기능): 편집 작업을 커맨드 객체로 기록합니다.
Go 언어 구현 (데이터베이스 트랜잭션 시뮬레이션)
package command import ( "database/sql" "fmt" ) // DatabaseReceiver 데이터베이스 수신자 type DatabaseReceiver struct { db *sql.DB } func (r *DatabaseReceiver) ExecuteSQL(sqlStmt string) error { fmt.Printf("Executing: %s\n", sqlStmt) return nil // SQL 실행 시뮬레이션 } func (r *DatabaseReceiver) Rollback() error { fmt.Println("Rolling back transaction") return nil // 롤백 시뮬레이션 } // Command 커맨드 인터페이스 type Command interface { Execute() error Undo() error } // InsertCommand 삽입 커맨드 type InsertCommand struct { receiver *DatabaseReceiver table string columns []string values []string prevValues map[string]string // 롤백을 위한 이전 값 저장 } func (c *InsertCommand) Execute() error { // 삽입 로직 실행 및 이전 값 기록 c.prevValues = getPreviousValues(c.receiver, c.table, c.columns) return c.receiver.ExecuteSQL(fmt.Sprintf("INSERT INTO %s VALUES (%s)", c.table, c.values)) } func (c *InsertCommand) Undo() error { // prevValues를 사용하여 삽입 작업 롤백 return c.receiver.Rollback() }
9. 컴포지트 패턴
패턴 정의
객체들을 트리 구조로 결합하고, 개별 객체(리프)와 복합 객체(컨테이너)를 통일되게 처리합니다. 구조 패턴에 속하며, 계층적 관리 시나리오에 적합합니다.
핵심 특징
- 트리 구조: 부분-대 전체 계층 관계를 지원합니다.
- 통일된 인터페이스: 클라이언트는 리프와 컨테이너를 일관되게 처리합니다.
- 재귀적 처리: 컨테이너는 다른 컨테이너나 리프를 포함할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 계층 구조 작업 단순화 | 높은 설계 복잡도 |
| 복잡한 계층 순회 지원 | 리프와 컨테이너의 인터페이스가 엄격하게 통일되어야 함 |
| 개방-폐쇄 원칙 준수 | 기능 확장이 전체 구조에 영향을 미칠 수 있음 |
시나리오 애플리케이션
- 파일 시스템 (AWS S3의 버킷/객체 구조): 파일과 폴더를 통일되게 처리합니다.
- 조직 구조 (기업 HR 시스템의 부서/직원 관리): 부서는 하위 부서와 직원을 포함할 수 있습니다.
- 전자상거래 상품 카탈로그 (Amazon의 카테고리/하위 카테고리/상품 계층): 계층적 상품 관리.
- GUI 구성 요소 (React Native의 View/Text 컴포넌트 중첩): UI 컴포넌트 트리를 통일되게 처리합니다.
Go 언어 구현 (파일 시스템 시뮬레이션)
package composite import "fmt" // FileSystemNode 파일 시스템 노드 인터페이스 type FileSystemNode interface { List() string Add(node FileSystemNode) Remove(node FileSystemNode) } // File 리프 노드: 파일 type File struct { name string size int } func (f *File) List() string { return fmt.Sprintf("File: %s (%dKB)", f.name, f.size) } func (f *File) Add(node FileSystemNode) {} func (f *File) Remove(node FileSystemNode) {} // Directory 컨테이너 노드: 디렉토리 type Directory struct { name string children []FileSystemNode } func (d *Directory) List() string { list := fmt.Sprintf("Directory: %s\n", d.name) for _, child := range d.children { list += fmt.Sprintf(" ├─ %s\n", child.List()) } return list } func (d *Directory) Add(node FileSystemNode) { d.children = append(d.children, node) } func (d *Directory) Remove(node FileSystemNode) { for i, child := range d.children { if child == node { d.children = append(d.children[:i], d.children[i+1:]...) return } } }
10. 이터레이터 패턴
패턴 정의
컬렉션의 내부 데이터 구조를 숨기고, 컬렉션 요소를 순회하기 위한 통일된 인터페이스를 제공합니다. 행동 패턴에 속하며, 데이터 순회 시나리오에 적합합니다.
핵심 특징
- 추상 순회: 클라이언트는 컬렉션의 내부 구현을 알 필요가 없습니다.
- 다중 순회 모드: 순방향, 역방향, 필터링과 같은 순회 전략을 지원합니다.
- 컬렉션 분리: 컬렉션과 이터레이터는 독립적으로 발전할 수 있습니다.
장단점
| 장점 | 단점 |
|---|---|
| 컬렉션 접근 인터페이스 통일 | 이터레이터 클래스의 설계 비용 증가 |
| 복잡한 데이터 구조 순회 지원 | 이터레이터 사용자 정의는 클래스 과다 증가를 유발할 수 있음 |
| 단일 책임 원칙 준수 | 이터레이터는 순회 상태를 유지해야 함 |
시나리오 애플리케이션
- 빅데이터 처리 (Hadoop MapReduce의 데이터셋 순회): 다양한 스토리지 형식을 일관되게 처리합니다.
- 데이터베이스 ORM (GORM의 결과 집합 순회): 다양한 데이터베이스의 반환 형식을 투명하게 처리합니다.
- 그래픽 렌더링 (Three.js의 장면 그래프 노드 순회): 3D 객체의 계층 구조를 일관되게 처리합니다.
- 로그 분석 (ELK의 로그 항목 순회): 다양한 로그 스토리지 형식의 순회를 지원합니다.
Go 언어 구현 (사용자 정의 컬렉션 이터레이터)
package iterator import "fmt" // Collection 컬렉션 인터페이스 type Collection interface { CreateIterator() Iterator AddItem(item string) } // StringCollection 문자열 컬렉션 구현 type StringCollection struct { items []string } func (c *StringCollection) CreateIterator() Iterator { return &StringIterator{collection: c, index: -1} } func (c *StringCollection) AddItem(item string) { c.items = append(c.items, item) } // Iterator 이터레이터 인터페이스 type Iterator interface { Next() bool Current() string } // StringIterator 문자열 이터레이터 구현 type StringIterator struct { collection *StringCollection index int } func (i *StringIterator) Next() bool { i.index++ return i.index < len(i.collection.items) } func (i *StringIterator) Current() string { if i.index < len(i.collection.items) { return i.collection.items[i.index] } return "" } // 사용 예제 func TraverseCollection(collection Collection) { iterator := collection.CreateIterator() for iterator.Next() { fmt.Println(iterator.Current()) } }
요약
Go 언어는 인터페이스와 컴포지션 기능을 통해 디자인 패턴 구현에 유연한 지원을 제공합니다:
- 생성 패턴: 싱글톤 패턴을 사용하여 전역 상태를 제어하고, 팩토리 패턴을 사용하여 객체 생성을 캡슐화합니다.
- 구조 패턴: 컴포지션을 통해 데코레이터, 프록시, 어댑터의 기능적 확장을 달성합니다.
- 행동 패턴: 인터페이스의 도움을 받아 옵저버, 전략, 커맨드의 상호 작용 로직을 분리하고 구현합니다.
실제 개발에서는 특정 시나리오에 따라 적절한 패턴을 선택해야 합니다:
- 마이크로서비스 아키텍처의 경우 팩토리 패턴과 어댑터 패턴을 선호합니다.
- 이벤트 기반 시스템의 경우 옵저버 패턴과 커맨드 패턴을 권장합니다.
- 계층적 데이터 관리를 위해서는 컴포지트 패턴과 이터레이터 패턴이 첫 번째 선택입니다.
디자인 패턴의 합리적인 사용은 코드의 유지보수성, 확장성, 재사용성을 향상시킬 수 있습니다. 단, 과도한 설계는 피해야 하며, 항상 실제 문제를 해결하는 데 집중해야 합니다.
Leapcell: 최고의 서버리스 웹 호스팅
마지막으로, Go 서비스를 배포하는 데 가장 적합한 플랫폼인 **Leapcell**을 추천합니다.

🚀 선호하는 언어로 구축
JavaScript, Python, Go 또는 Rust로 손쉽게 개발하세요.
🌍 무료로 무제한 프로젝트 배포
사용하는 만큼만 지불하세요. 요청 수, 요금 없음.
⚡ 사용한 만큼 지불, 숨겨진 비용 없음
유휴 수수료 없이 원활한 확장성을 제공합니다.

🔹 Twitter 팔로우: @LeapcellHQ