[디자인 패턴] Factory pattern in Swift

Ryan (Geonhee) Son·2021년 9월 20일
3

Study Stack

목록 보기
28/34

목차로 돌아가기

소개

팩토리 또는 팩토리 메서드 패턴 (Factory pattern or factory method pattern)은 생성 관점의 디자인 패턴 (Creational design patterns)의 일종으로, 인스턴스 생성을 팩토리 타입의 메서드에 위임하는 방식으로 개발자들에게 이용하는 타입에 대한 정보를 숨기고 인스턴스 생성을 용이하게 해줍니다.

Example

가정

현재 개발 중인 앱에는 자주 사용되는 UI 요소들을 커스터마이징한 커스텀 UI 타입이 있습니다.

패턴을 적용하지 않은 경우

import UIKit

final class MyAppLabel: UILabel {
    
    init(textColor: CGColor = UIColor.label.cgColor, backgroundColor: UIColor = .systemBackground) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}


final class MyAppButton: UIButton {

    init(textColor: CGColor, backgroundColor: UIColor = .systemBackground) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}

final class MyAppTextField: UITextField {

    init(textColor: CGColor = UIColor.label.cgColor, backgroundColor: UIColor) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}

각 타입에는 이니셜라이저를 통해 기본으로 설정된 값도 있고, 그렇지 않은 경우도 있습니다. 개발자들은 UI를 개발하는 동안 모든 커스텀 타입에 대해 이러한 세부 사항을 기억하고 있어야 합니다. 현재는 textColorbackgroundColor에 대한 사항만을 가정하고 있지만, 실제로는 크기 또는 여백 등 더 많은 커스터마이징 요소들이 포함되어 있을 수 있습니다. 팩토리 패턴이 적용되지 않은 현재는 아래와 같이 직접 UI 요소들을 초기화하여 사용하고 있습니다.

let label = MyAppLabel()
let button = MyAppButton(textColor: UIColor.systemPink.cgColor)
let textField = MyAppTextField(backgroundColor: .systemTeal)

하지만 개발자들이 모든 커스텀 타입에 대해 이러한 세부 사항을 기억하는 것은 쉽지 않은 일일 것입니다.

패턴을 적용한 경우

그래서 각 UI 요소들을 열거형을 통해 케이스를 정의하고, 프로토콜을 통해 외부에 제공해야할 인터페이스를 정의하도록 만들어 케이스별로 특정한 UI 요소를 지칭할 수 있는 환경을 만들어줍니다.

import UIKit

enum UIComponent {
    case label, button, textField
}

protocol MyAppUIComponent {

    var component: UIComponent { get }
    var textColor: CGColor { get set }
    var backgroundColor: UIColor { get set }
}


final class MyAppLabel: UILabel, MyAppUIComponent {
    
    var component: UIComponent { .label }
    
    init(textColor: CGColor = UIColor.label.cgColor, backgroundColor: UIColor = .systemBackground) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}


final class MyAppButton: UIButton, MyAppUIComponent {

    var component: UIComponent { .button }

    init(textColor: CGColor, backgroundColor: UIColor = .systemBackground) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}

final class MyAppTextField: UITextField, MyAppUIComponent {
    
    var component: UIComponent { .textField }

    init(textColor: CGColor = UIColor.label.cgColor, backgroundColor: UIColor) {
        self.textColor = textColor
        self.backgroundColor = backgroundColor
    }
}

계속해서 정의한 커스텀 UI 요소의 생성을 전문으로하는 팩토리 타입을 만듭니다.

struct ComponentFactory {
    
    func make(_ component: UIComponent) -> MyAppUIComponent {
        switch component {
        case .label:
            return MyAppLabel()
        case .button:
            return MyAppButton(textColor: UIColor.systemPink.cgColor)
        case .textField:
            return MyAppTextField(backgroundColor: .systemTeal)
        }
    }
}

이제 팩토리 타입을 이용해 원하는 UI 요소를 케이스별로 생성하여 사용할 수 있게 되었습니다. 개발자들이 UI 요소를 생성할 때 많은 것을 알 필요가 없게 되었네요.

let factory = ComponentFactory()

let label = factory.make(.label)
let button = factory.make(.button)
let textField = factory.make(.textField)

새로운 커스텀 UI 타입을 정의한다고 하더라도 인스턴스 생성에 대한 세부 사항은 팩토리 타입에서 정의해주면 됩니다. 열거형의 케이스로 정의되어 있기 때문에 새로운 케이스에 대한 생성 방식을 팩토리 타입의 make(_:) 메서드에 정의하지 않으면 컴파일 에러가 발생하여 에러 발견이 더 용이해진다는 장점도 생겼습니다.

목차로 돌아가기

참고자료

  1. Design Patterns in Swift - ochococo GitHub Repository
  2. 객체지향 디자인패턴 2 - 얄팍한 코딩사전
profile
합리적인 해법 찾기를 좋아합니다.

1개의 댓글

comment-user-thumbnail
2022년 4월 14일

깔끔한 정리 감사합니다! 이해가 쏙쏙 되네요!

답글 달기