iOS 개발을 하다 보면 남의 코드에서 init(...) 대신 static func make(...) 같은 걸 만나고 갸웃했던 적 있으실 거예요.
먼저 결론부터 말씀드릴게요.
Swift 정적 팩토리 메서드는 생성 과정에 이름을 붙이고, 반환 타입을 유연하게 바꾸고, 객체 재사용까지 제어할 수 있어서 init만으로는 답답할 때 꺼내 쓰는 카드입니다.
오늘은 init 대신 static func make를 쓰는 이유를 실무 관점에서 하나씩 풀어볼게요.
정적 팩토리 메서드가 대체 뭔가요?
말은 거창한데 개념은 단순해요.
객체를 만들어 돌려주는 static 메서드예요. 생성자를 직접 부르는 대신, 생성을 감싼 함수를 하나 두는 거죠.
아래처럼 생겼어요.
struct Button {
let title: String
let style: Style
// init을 감싼 정적 팩토리 메서드
static func makePrimary(title: String) -> Button {
Button(title: title, style: .primary)
}
}
호출부는 Button.makePrimary(title: "확인") 이렇게 돼요.
Button(title:style:)를 직접 부르는 것과 결과는 같아요. 다만 “어떤 버튼을 만드는지”가 이름에 드러나죠.
이 작은 차이가 실무에선 꽤 크게 작용합니다.
init 대신 make를 쓰는 이유 4가지
제가 실제로 체감한 장점을 꼽아 볼게요.
1. 이름으로 의도를 드러낼 수 있어요
생성자는 이름이 전부 init으로 똑같아요. 파라미터 조합으로만 구분되죠.
그래서 비슷한 init이 여러 개면 헷갈립니다. make(fromJSON:), make(withDefaults:)처럼 이름을 붙이면 호출부만 봐도 뭘 만드는지 읽혀요.
2. 매번 새 객체를 안 만들어도 돼요
init은 호출할 때마다 무조건 새 인스턴스를 만듭니다.
반면 팩토리 메서드는 캐시된 객체나 이미 있는 싱글턴을 돌려줄 수 있어요. Bool의 참·거짓처럼 값이 정해진 경우엔 재사용이 훨씬 이득이죠.
3. 반환 타입을 유연하게 바꿀 수 있어요
이게 개인적으로 제일 강력하다고 느낀 부분이에요.
팩토리 메서드는 선언된 타입의 하위 타입이나 프로토콜 구현체를 돌려줄 수 있습니다. 호출하는 쪽은 구체 타입을 몰라도 되고요.
protocol Shape { func area() -> Double }
enum ShapeFactory {
// 조건에 따라 다른 구현체를 반환
static func make(sides: Int) -> Shape {
sides == 4 ? Square() : Triangle()
}
}
make(sides:)의 반환 타입은 Shape 하나지만, 실제로는 상황에 맞는 구현체가 나와요.
4. 실패를 부드럽게 처리할 수 있어요
init?이나 throws로도 되지만, 팩토리 메서드는 반환값 자체를 옵셔널로 두거나 Result로 감싸기 편해요. 생성 로직이 복잡할 때 흐름이 깔끔해집니다.
init이랑 뭐가 다를까? 한눈에 비교
헷갈리실 것 같아 표로 정리했어요.
| 구분 | init (생성자) | static func make (정적 팩토리) |
|---|---|---|
| 이름 | 항상 init 고정 | 자유롭게 지정 |
| 새 인스턴스 | 매번 강제 생성 | 재사용·캐싱 가능 |
| 반환 타입 | 자기 타입만 | 하위 타입·프로토콜 가능 |
| 실패 처리 | init? / throws | 옵셔널·Result 등 자유 |
| 단점 | 이름 구분 불가 | 서브클래싱 제약, 발견성 낮음 |
단점도 솔직하게 짚고 갈게요.
팩토리 메서드만 있고 public init이 없으면, 그 타입은 상속으로 확장하기 어려워요.
또 생성자는 자동완성에서 바로 뜨지만, make는 이름을 알아야 찾기 쉬워서 발견성이 조금 떨어집니다. 그래서 make, create, from 같은 관례적인 이름을 쓰는 걸 추천해요.
그래서 언제 쓰면 되나요?
제가 실무에서 나눠 쓰는 기준은 이래요.
- 단순히 저장 프로퍼티만 채우면 될 때 → 그냥
init - 생성 방식이 여러 갈래라 이름으로 구분하고 싶을 때 →
make - 조건에 따라 다른 타입을 돌려줘야 할 때 →
make - 객체를 재사용하거나 캐싱하고 싶을 때 →
make
정리하면, 생성이 “그냥 값 채우기”를 넘어 하나의 결정 과정이 될 때 팩토리 메서드가 빛을 발해요.
반대로 모든 생성을 make로 감싸면 오히려 코드가 장황해집니다. 필요할 때만 골라 쓰는 게 핵심이에요.
처음엔 낯설게 느껴지실 수 있는데, 한 번 의도가 잡히면 코드 읽는 맛이 달라집니다. 다음에 비슷한 상황을 만나면 make를 한번 시도해 보세요. 분명 도움이 되실 거예요 🙂
