apple/DesignPattern, Architecture
Swift 디자인패턴 Factory Pattern (팩토리 패턴)
lgvv
2022. 5. 8. 15:05
Swift 디자인패턴 Factory Pattern (팩토리 패턴)
Factory Pattern은 객체 생성을 캡슐화하여, 클라이언트가 객체 생성 방식에 대해 알 필요 없도록 설계하는 생성 패턴
이를 통해 객체 생성 로직을 중앙 집중화하고, 유지보수를 용이하게 함.
히스토리
- 2022-05-08: 디자인 패턴 스터디 정리
- 2024-11-28: 포스팅 글 재정리 및 예제 변경
Factory Pattern
팩토리 패턴은 다른 개념으로도 확장 가능
- 단순 팩토리 패턴: 조건에 따라 객체를 생성하는 메서드만 제공 (정식 팩토리 패턴은 아님)
- 팩토리 메서드 (Factory Method) 패턴: 서브클래스에서 객체 생성 과정을 오버라이드하여 생성 로직을 확장
- 추상 팩토리 (Abstract Factory) 패턴: 관련 객체군을 생성하기 위한 인터페이스를 제공해, 구체적인 객체 없이 생성 가능
팩토리 패턴 장점
- 객체 생성 로직의 재사용성 증가
- 코드 유지보수성 향상
- 클라이언트 객체 생성 로직 간의 느슨한 결합 제공
단점
- 클래스 계층이 깊어질 경우 코드 복잡도 증가할 수 있음
코드 예시
팩토리 패턴을 활용해 동아리 지원자 시스템 구축 해보기
import SwiftUI
struct Applicant {
var name: String
var email: String
var phase: Phase
enum Phase {
case applied // 지원 완료
case assignment // 사전과제
case interview // 인터뷰
case accepted // 합격
case rejected // 탈락
}
}
struct Email {
var subject: String
var message: String
}
struct EmailFacotry {
func create(applicant: Applicant) -> Email {
switch applicant.phase {
case .applied:
return .init(subject: "서류 제출 완료", message: "제출 완료 되었습니다")
case .assignment:
return .init(subject: "사전과제 안내", message: "사전과제 해주세요")
case .interview:
return .init(subject: "면접 안내", message: "화상면접 들어와주세요")
case .accepted:
return .init(subject: "합격 안내", message: "최종합격 했어요")
case .rejected:
return .init(subject: "불합격 안내", message: "다음기회에 다시 지원해주세요")
}
}
}
private struct ContentView: View {
var body: some View {
Button("Execute") {
let facotry = EmailFacotry()
var applicant = Applicant(
name: "name",
email: "email@example.com",
phase: .applied
)
print(facotry.create(applicant: applicant))
applicant.phase = .assignment
print(facotry.create(applicant: applicant))
applicant.phase = .interview
print(facotry.create(applicant: applicant))
applicant.phase = .accepted
print(facotry.create(applicant: applicant))
applicant.phase = .rejected
print(facotry.create(applicant: applicant))
}
}
}
#Preview {
ContentView()
}
코드 예시 (단순 팩토리 패턴)
import SwiftUI
enum VehicleType {
case car
case bike
}
protocol Vehicle {
func drive()
}
class Car: Vehicle {
func drive() {
print("Driving a car!")
}
}
class Bike: Vehicle {
func drive() {
print("Riding a bike!")
}
}
class VehicleFactory {
static func createVehicle(type: VehicleType) -> Vehicle {
switch type {
case .car:
return Car()
case .bike:
return Bike()
}
}
}
private struct ContentView: View {
var body: some View {
Button("Execute") {
let car = VehicleFactory.createVehicle(type: .car)
car.drive()
}
}
}
#Preview {
ContentView()
}
코드 예시 (팩토리 메서드 패턴)
import SwiftUI
protocol Transport {
func deliver()
}
class Truck: Transport {
func deliver() {
print("Delivering by truck!")
}
}
class Ship: Transport {
func deliver() {
print("Delivering by ship!")
}
}
protocol Logistics {
func createTransport() -> Transport
}
class RoadLogistics: Logistics {
func createTransport() -> Transport {
return Truck()
}
}
class SeaLogistics: Logistics {
func createTransport() -> Transport {
return Ship()
}
}
private struct ContentView: View {
var body: some View {
Button("Execute") {
// 사용 예시
let roadLogistics = RoadLogistics()
let transport = roadLogistics.createTransport()
transport.deliver() // Output: Delivering by truck!
}
}
}
#Preview {
ContentView()
}
코드 예시 (추상 팩토리 패턴)
import SwiftUI
fileprivate protocol Button {
func render()
}
fileprivate protocol Checkbox {
func toggle()
}
fileprivate class MacOSButton: Button {
func render() {
print("Rendering MacOS button.")
}
}
fileprivate class MacOSCheckbox: Checkbox {
func toggle() {
print("Toggling MacOS checkbox.")
}
}
fileprivate class WindowsButton: Button {
func render() {
print("Rendering Windows button.")
}
}
fileprivate class WindowsCheckbox: Checkbox {
func toggle() {
print("Toggling Windows checkbox.")
}
}
fileprivate protocol UIFactory {
func createButton() -> Button
func createCheckbox() -> Checkbox
}
fileprivate class MacOSFactory: UIFactory {
func createButton() -> Button {
return MacOSButton()
}
func createCheckbox() -> Checkbox {
return MacOSCheckbox()
}
}
fileprivate class WindowsFactory: UIFactory {
func createButton() -> Button {
return WindowsButton()
}
func createCheckbox() -> Checkbox {
return WindowsCheckbox()
}
}
private struct ContentView: View {
var body: some View {
SwiftUI.Button("Execute") {
// 사용 예시
let factory: UIFactory = MacOSFactory()
let button = factory.createButton()
button.render() // Output: Rendering MacOS button.
}
}
}
#Preview {
ContentView()
}
(참고)
https://www.raywenderlich.com/books/design-patterns-by-tutorials/v3.0/chapters/11-factory-pattern
https://refactoring.guru/ko/design-patterns/factory-method
https://refactoring.guru/ko/design-patterns/abstract-factory