lgvv98

[Swift] Factory Pattern 본문

apple/DesignPattern & Architecture

[Swift] Factory Pattern

lgvv 2022. 5. 8. 15:05

Factory Pattern

 

✅ Factory Pattern

 

아래의 문서를 구입하여 영어 문서를 번역하고 이해한 것을 바탕으로 글을 작성하고 있습니다.

https://www.raywenderlich.com/books/design-patterns-by-tutorials/v3.0/chapters/11-factory-pattern

 

Design Patterns by Tutorials, Chapter 11: Factory Pattern

The factory pattern provides a way to create objects without exposing creation logic. Technically, there are multiple "flavors" of this pattern, including a simple factory, abstract factory and others. However, each of these share a common goal: to isolate

www.raywenderlich.com

 

팩토리 패턴은 생성 로직을 노출없이 객체를 만드는 방법을 제공하는 생성 패턴입니다. 여기에서 2가지 유형이 포함되어 있습니다.

팩토리 패턴

 

1. Factory는 객체를 만듭니다.

2. Product는 생성된 객체입니다.

 

기술적으로 단순히 Factory, 추상 Factory 등을 포함하여 이 패턴의 여러 "flavors"가 있습니다. 하지만 이들 각각은 자체 구성 내에서 객체 생성 논리를 분리하는 공통 목표를 공유합니다.

 

이번 챕터에서는 이전 챕터의 프로젝트의 Coffee Quest에 추가하여 간단한 Factory에 대해 공부합니다. 공통 유형 또는 프로토콜의 객체를 생성하며, 팩토리 유형 자체를 소비자가 직접 알고 사용합니다.

 

 

When should you use it?

consumers가 products를 직접적으로 생성하게 하는 대신 product 생성 로직을 분리하고 싶을 때마다 팩토리 패턴을 사용하세요.

 

팩토리는 다형성(polymorohic) 서브클래스 또는 동일한 프로토콜을 구현하는 여러 객체와 같은 관련 그룹이 있을 때 매우 유용합니다!

예를 들면은 Factory를 사용해서 네트워크 응답을 검사하고 구체적은 하위 모델로 타입을 전환할 수 있습니다.

 

Factory는 단일 Product 유형이 있는 경우에도 유용하지만 이를 생성하려면 종속성 또는 정보를 제공해야 합니다. 예를 들면, Factory를 사용하여 "구직 지원자 응답" 이메일을 만들 수 있습니다. Factory는 후보자가 수락, 거부 또는 인터뷰가 필요한지 여부에 따라 이메일 세부 정보를 제공할 수 있습니다.

 

Playground example

 

구직자 응답 이메일을 생성하기 위해서 Factory를 생성합니다.

import Foundation

public struct JobApplicant {
  public let name: String
  public let email: String
  public var status: Status
  
  public enum Status {
    case new
    case interview
    case hired
    case rejected
  }
}

public struct Email {
  public let subject: String
  public let messageBody: String
  public let recipientEmail: String
  public let senderEmail: String
}

JobApplicant를 정의하고 Email을 모델링 했습니다.

 

아래의 코드를 추가합니다!

// 1
public struct EmailFactory {
  
  // 2
  public let senderEmail: String
  
  // 3
  public func createEmail(to recipient: JobApplicant) -> Email {
    let subject: String
    let messageBody: String

    switch recipient.status {
    case .new:
      subject = "We Received Your Application"
      messageBody = 
        "Thanks for applying for a job here! " +
        "You should hear from us in 17-42 business days."

    case .interview:
      subject = "We Want to Interview You"
      messageBody = 
        "Thanks for your resume, \(recipient.name)! " +
        "Can you come in for an interview in 30 minutes?"

    case .hired:
      subject = "We Want to Hire You"
      messageBody = 
        "Congratulations, \(recipient.name)! " +
        "We liked your code, and you smelled nice. " +
        "We want to offer you a position! Cha-ching! $$$"

    case .rejected:
      subject = "Thanks for Your Application"
      messageBody = 
        "Thank you for applying, \(recipient.name)! " +
        "We have decided to move forward " +
        "with other candidates. " +
        "Please remember to wear pants next time!"
    }

    return Email(subject: subject,
                 messageBody: messageBody,
                 recipientEmail: recipient.email,
                 senderEmail: senderEmail)
  }
}

위의 코드가 하는 일은 다음과 같습니다.

1. EmailFactory 구조체를 만듭니다.

2. senderEamil에 대한 공용 속성을 만듭니다.

3. JobApplicant를 받아 Email을 반환하는 createEmail이라는 함수를 만듭니다. 

createEmail 안에 JobApplicant의 상태에 대한 switch case를 추가하여 제목 및 messageBody 변수를 Email에 대한 적절한 데이터로 채웁니다.

 

아래에 EmailFactory 정의한 코드를 추가하세요.

var jackson = JobApplicant(name: "Jackson Smith",
                           email: "jackson.smith@example.com",
                           status: .new)

let emailFactory = 
  EmailFactory(senderEmail: "RaysMinions@RaysCoffeeCo.com")

// New
print(emailFactory.createEmail(to: jackson), "\n")

// Interview
jackson.status = .interview
print(emailFactory.createEmail(to: jackson), "\n")

// Hired
jackson.status = .hired
print(emailFactory.createEmail(to: jackson), "\n")

여기서 "Jackson Smith"라는 새 구직자를 만듭니다. 그런 다음 새 EmailFactory 인스턴스를 생성하고 마지막으로 이 인스턴스를 사용하여 JobApplicant 개체 상태 속성을 기반으로 이메일을 생성합니다.

잭슨이 곧 취직할 것 같아요. 그는 아마도 디자인 패턴에 대한 그의 폭넓은 지식으로 레이 커피 회사에 깊은 인상을 줌으로써 다른 지원자들과 차별화되었을 것입니다!

 

 

What should you be careful about?

모든 다형성 객체가 Factory를 필요로 하는 것은 아닙니다. 객체가 매우 간단한 경우 뷰 컨트롤러 자체와 같이 항상 생성 논리를 직접 소비자에게 적용할 수 있습니다.

또는 객체를 빌드하기 위해 일련의 단계가 필요한 경우 builder 패턴이나 다른 패턴을 대신 사용하는 것이 좋습니다.

 

 

 

Tutorial project

팩토리 패턴은 개발하면서 자연스럽게 종종 사용하던 패턴이다

그냥 생성로직을 분리하는 것 뿐!

 

https://github.com/lgvv/DesignPattern/tree/main/factory-pattern/CoffeeQuest

 

GitHub - lgvv/DesignPattern: ✨ 디자인 패턴을 공부합니다!

✨ 디자인 패턴을 공부합니다! Contribute to lgvv/DesignPattern development by creating an account on GitHub.

github.com

 

(* 개인의견) 팩토리 패턴은 모델을 만들어서 거기에 원하는 데이터 값을 주면 해당하는 데이터 타입으로 바꾸어 리턴해줌.

 

팩토리 패턴의 사용 예시

 

 

 

Key points

이번 챕터에서는 팩토리 패턴에 대해서 배웠습니다.

 

 - Factory의 목표는 자신의(isolate) 구조 내에서 생성 로직을 분리하는 것입니다.

 - Factory는 관련 Product가 있거나 추가 정보가 제공될 때까지 객체를 생성할 수 없는 경우(예시: 네트워크 호출 완료 또는 사용자 입력을 대기)에 가장 유용합니다! 

 - Factory 메소드는 객체를 생성하기 위해 추상화 계층을 추가하여 중복 코드를 줄입니다.

 

다시 한 번 ViewController 줄여 보았습니다. 앱에서 시각적으로 많이 변경되지는 않았지만 factory를 구현하면 프로젝트가 불가피하게 커질 때 쉽게 변경할 수 있습니다.

'apple > DesignPattern & Architecture' 카테고리의 다른 글

[Swift] Iterator Pattern  (0) 2022.05.13
[Swift] Adapter Pattern  (2) 2022.05.13
[Swift] MVVM Pattern  (0) 2022.04.26
[Swift] Builder Pattern  (0) 2022.04.22
[Swift] Observer Pattern  (0) 2022.04.19
Comments