팩토리 패턴

2025. 3. 25. 18:11·디자인패턴

팩토리 패턴이란 무엇인가?

팩토리 패턴은 객체 생성을 캡슐화하는 생성 패턴 중 하나입니다. 

직접 init()을 호출해서 객체를 만드는 대신, 팩토리라는 중간 관리자를 두고 이를 통해 객체를 생성하는 방식이에요.

저도 처음 iOS 개발을 시작했을 때는 그냥 필요한 곳에서 바로 객체를 만들면 되는 거 아닌가? 라고 생각했었는데,

프로젝트가 커질수록 이런 방식의 문제점을 절실히 느끼게 되더라고요 😅

왜 팩토리 패턴을 사용해야 할까?

1. 런타임에 객체 타입 결정

사용자 입력이나 네트워크 응답에 따라 다른 타입의 객체를 만들어야 할 때가 있어요.

예를 들어, SNS 앱에서 피드 타입(텍스트, 이미지, 비디오)에 따라 다른 셀을 생성해야 하는 경우입니다.

2. 복잡한 초기화 로직 숨기기

객체를 만들 때 복잡한 설정이나 의존성 주입이 필요한 경우, 클라이언트 코드가 이런 복잡성을 알 필요가 없죠.

3. 확장성 보장

새로운 타입이 추가될 때마다 기존 코드를 수정하는 것이 아니라, 팩토리만 확장하면 되니까 개방-폐쇄 원칙(OCP)을 지킬 수 있어요.

이런 장점들 때문에 팩토리 메서드 패턴은 코드에 높은 수준의 유연성을 제공해야 할 때 매우 유용합니다.

팩토리 메서드 패턴은 단일 객체 생성에 초점을 맞춘 패턴입니다. 하나의 제품을 만드는데, 그 제품의 구체적인 타입은 서브클래스가 결정하도록 하는 방식이에요.

실제 상황: 배송 관리 앱 📦📦📦 + 🚢?

iOS 앱에서 배송 관리 시스템을 만든다고 가정해봅시다. 처음에는 트럭 배송만 지원했는데,

갑자기 선박 배송도 추가해달라는 요청이 들어왔어요.

기존 방식이라면:

// 기존 코드 - 문제가 있는 방식
func createDelivery(type: String) -> Transport {
    if type == "truck" {
        return Truck()
    } else if type == "ship" {
        return Ship()
    } else {
        fatalError("Unknown transport type")
    }
}

 

이렇게 하면 새로운 운송 수단이 추가될 때마다 이 함수를 계속 수정해야 하겠죠?
그리고 만약 비행기, 드론 등이 추가된다면? 조건문 지옥이 펼쳐질 거예요 😱

팩토리 메서드 패턴으로 해결하기

// Product 프로토콜 - 모든 운송 수단의 공통 인터페이스
protocol Transport {
    func deliver() -> String
    func getCapacity() -> Int
    func getSpeed() -> Int
}

// Concrete Products - 구체적인 운송 수단들
class Truck: Transport {
    func deliver() -> String {
        return "🚛 육로로 배송 중입니다"
    }
    
    func getCapacity() -> Int { return 1000 }
    func getSpeed() -> Int { return 80 }
}

class Ship: Transport {
    func deliver() -> String {
        return "🚢 해상으로 배송 중입니다"
    }
    
    func getCapacity() -> Int { return 5000 }
    func getSpeed() -> Int { return 30 }
}

class Airplane: Transport {
    func deliver() -> String {
        return "✈️ 항공으로 배송 중입니다"
    }
    
    func getCapacity() -> Int { return 800 }
    func getSpeed() -> Int { return 900 }
}

// Creator 프로토콜 - 팩토리 메서드를 정의
protocol Logistics {
    func createTransport() -> Transport  // 팩토리 메서드
    func planDelivery() -> String
}

// 비즈니스 로직을 포함한 기본 구현
extension Logistics {
    func planDelivery() -> String {
        let transport = createTransport()
        let deliveryInfo = transport.deliver()
        let capacity = transport.getCapacity()
        let speed = transport.getSpeed()
        
        return """
        \(deliveryInfo)
        적재량: \(capacity)kg, 속도: \(speed)km/h
        """
    }
}

// Concrete Creators - 구체적인 물류 팩토리들
class RoadLogistics: Logistics {
    func createTransport() -> Transport {
        return Truck()
    }
}

class SeaLogistics: Logistics {
    func createTransport() -> Transport {
        return Ship()
    }
}

class AirLogistics: Logistics {
    func createTransport() -> Transport {
        return Airplane()
    }
}

클라이언트 코드가 얼마나 깔끔해지는지 봅시다

class DeliveryManager {
    func processDelivery(logistics: Logistics) {
        print(logistics.planDelivery())
    }
}

// 사용 예시
let manager = DeliveryManager()

manager.processDelivery(logistics: RoadLogistics())
// 출력: 🚛 육로로 배송 중입니다
//       적재량: 1000kg, 속도: 80km/h

manager.processDelivery(logistics: SeaLogistics())
// 출력: 🚢 해상으로 배송 중입니다
//       적재량: 5000kg, 속도: 30km/h
이제 새로운 운송 수단이 추가되어도 기존 코드는 전혀 건드릴 필요가 없어요!
새로운 Transport 구현체와 Logistics 구현체만 만들면 됩니다.

추상 팩토리 패턴

관련된 객체들의 집합을 생성하는 데 초점을 맞춘 패턴입니다.

- 어떻게 호환되는 객체 군을 생성할 것인가에 초점

실제 상황: 가구 쇼핑 앱 🛋️🛋️

가구 앱을 만든다고 해봅시다. 고객들은 모던 스타일로 맞춘 세트나 구찌 스타일로 맞춘 세트를 원해요.

각 스타일별로 의자, 소파, 테이블이 모두 일관된 디자인을 가져야 하죠.

// Abstract Products - 가구의 공통 인터페이스
protocol Chair {
    func sitOn() -> String
    func getDesignDetails() -> String
}

protocol Sofa {
    func lieOn() -> String
    func getDesignDetails() -> String
}

protocol Table {
    func placeItems() -> String
    func getDesignDetails() -> String
}

// Modern Style Concrete Products
class ModernChair: Chair {
    func sitOn() -> String {
        return "🪑 세련된 모던 의자에 앉았습니다"
    }
    
    func getDesignDetails() -> String {
        return "미니멀 디자인, 크롬 프레임, 가죽 시트"
    }
}

class ModernSofa: Sofa {
    func lieOn() -> String {
        return "🛋️ 편안한 모던 소파에 누웠습니다"
    }
    
    func getDesignDetails() -> String {
        return "L자형 디자인, 패브릭 소재, 낮은 백레스트"
    }
}

class ModernTable: Table {
    func placeItems() -> String {
        return "📱 유리 테이블에 물건을 올렸습니다"
    }
    
    func getDesignDetails() -> String {
        return "강화유리 상판, 스테인리스 다리"
    }
}

// Victorian Style Concrete Products
class VictorianChair: Chair {
    func sitOn() -> String {
        return "👑 고풍스러운 빅토리안 의자에 앉았습니다"
    }
    
    func getDesignDetails() -> String {
        return "조각 장식, 마호가니 원목, 벨벳 시트"
    }
}

class VictorianSofa: Sofa {
    func lieOn() -> String {
        return "🏰 럭셔리한 빅토리안 소파에 누웠습니다"
    }
    
    func getDesignDetails() -> String {
        return "카브리올 다리, 실크 소재, 높은 백레스트"
    }
}

class VictorianTable: Table {
    func placeItems() -> String {
        return "📜 고급스러운 원목 테이블에 물건을 올렸습니다"
    }
    
    func getDesignDetails() -> String {
        return "마호가니 원목, 조각 장식, 서랍 3개"
    }
}

// Abstract Factory - 가구 집합을 생성하는 인터페이스
protocol FurnitureFactory {
    func createChair() -> Chair
    func createSofa() -> Sofa
    func createTable() -> Table
}

// Concrete Factories - 스타일별 팩토리들
class ModernFurnitureFactory: FurnitureFactory {
    func createChair() -> Chair {
        return ModernChair()
    }
    
    func createSofa() -> Sofa {
        return ModernSofa()
    }
    
    func createTable() -> Table {
        return ModernTable()
    }
}

class VictorianFurnitureFactory: FurnitureFactory {
    func createChair() -> Chair {
        return VictorianChair()
    }
    
    func createSofa() -> Sofa {
        return VictorianSofa()
    }
    
    func createTable() -> Table {
        return VictorianTable()
    }
}

클라이언트에서 사용하기

class FurnitureShop {
    private let factory: FurnitureFactory
    
    init(factory: FurnitureFactory) {
        self.factory = factory
    }
    
    func setupShowroom() -> [String] {
        let chair = factory.createChair()
        let sofa = factory.createSofa()
        let table = factory.createTable()
        
        return [
            chair.sitOn(),
            sofa.lieOn(),
            table.placeItems(),
            "=== 디자인 세부사항 ===",
            chair.getDesignDetails(),
            sofa.getDesignDetails(),
            table.getDesignDetails()
        ]
    }
}

// 사용 예시
let modernShop = FurnitureShop(factory: ModernFurnitureFactory())
let victorianShop = FurnitureShop(factory: VictorianFurnitureFactory())

print("모던 쇼룸:")
modernShop.setupShowroom().forEach { print($0) }

print("\n빅토리안 쇼룸:")
victorianShop.setupShowroom().forEach { print($0) }

이렇게 하면 새로운 스타일(예: 스칸디나비아, 산업풍)이 추가되어도 기존 클라이언트 코드는 전혀 건드릴 필요가 없어요!

팩토리 메서드 vs 추상 팩토리

두 패턴의 핵심 차이점을 정리해보면:

특성 팩토리메서드 추상팩토리
초점 단일 객체 생성 관련된 객체 집합 생성
구현 방식 상속 (Inheritance) 구성 (Composition)
확장성 서브클래스 추가 새 팩토리 클래스 추가
복잡도 상대적으로 단순 더 복잡하지만 강력함

언제 어떤 것을 선택할까?

팩토리 메서드를 선택하는 경우:

  • 하나의 제품군 내에서 다양한 변형을 만들 때
  • 상속 구조가 자연스러운 경우
  • 상대적으로 단순한 객체 생성

추상 팩토리를 선택하는 경우:

  • 여러 관련 객체를 일관성 있게 생성해야 할 때
  • 런타임에 전체 제품군을 교체해야 할 때
  • 플랫폼별 또는 테마별 구현이 필요한 경우

저는 보통 단일 객체 생성이면 팩토리 메서드를, UI 테마나 플랫폼별 구현처럼 여러 관련 객체를 함께 다뤄야 하면 추상 팩토리를 선택해요.

참고자료

https://refactoring.guru/design-patterns/factory-method

 

Factory Method

/ Design Patterns / Creational Patterns Factory Method Also known as: Virtual Constructor Intent Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objec

refactoring.guru

 

https://refactoring.guru/design-patterns/factory-method

 

 

'디자인패턴' 카테고리의 다른 글

전략패턴  (0) 2025.09.29
커맨드 패턴  (0) 2025.05.20
데코레이터패턴  (1) 2025.05.19
파사드 패턴(Facade Pattern)  (0) 2025.03.25
Adaptor Pattern (구조적 디자인패턴)  (0) 2025.03.24
'디자인패턴' 카테고리의 다른 글
  • 커맨드 패턴
  • 데코레이터패턴
  • 파사드 패턴(Facade Pattern)
  • Adaptor Pattern (구조적 디자인패턴)
2료일
2료일
좌충우돌 모든것을 다 정리하려고 노력하는 J가 되려고 하는 세미개발자의 블로그입니다. 편하게 보고 가세요
  • 2료일
    GPT에게서 살아남기
    2료일
  • 전체
    오늘
    어제
    • 분류 전체보기 (133)
      • SWIFT개발일지 (28)
        • ARkit (1)
        • Vapor-Server with swift (3)
        • UIkit (2)
      • 알고리즘 (25)
      • Design (6)
      • iOS (42)
        • 반응형프로그래밍 (12)
      • 디자인패턴 (6)
      • CS (3)
      • 도서관 (2)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
2료일
팩토리 패턴
상단으로

티스토리툴바