CS/디자인패턴

[디자인패턴] Factory(팩토리) 패턴 with Swift

유정주 2023. 4. 21. 12:33
반응형

팩토리 패턴

팩토리 패턴은 팩토리 객체를 이용해 객체 생성 관심사를 분리하는 디자인 패턴입니다.

팩토리 메서드 패턴과 추상 팩토리 패턴으로 나뉘며 Swift에서는 프로토콜로 구현할 수 있습니다.

 

팩토리 패턴이 나오게 된 배경은 OCP(개방 폐쇄 원칙)와 연결지어 설명할 수 있습니다.

OCP는 확장에는 열려 있지만 변경에는 닫혀 있어야 한다는 원칙인데요.

닫혀 있어야 한다는 것은 확장을 했을 때 다른 부분에 영향을 주지 않아야 한다는 것을 의미합니다. (예시는 여기)

객체 생성 관심사를 분리해서 객체의 속성, 함수 등이 변경될 때 수정이 발생하는 범위를 최소화할 수 있습니다.

 

팩토리 메서드 패턴

팩토리 메서드 패턴은 인터페이스로 객체 생성 팩토리를 제공하고, 객체 생성 결정은 하위 클래스가 정하는 패턴입니다.

객체 생성을 캡슐화할 수 있으며 부모 클래스는 자식 클래스가 어떤 객체를 생성하는지 몰라도 됩니다.

(클래스라고 말하고 있지만 Swift는 프로토콜을 채택한 구조체도 포함합니다.)

 

https://cjw-awdsd.tistory.com/54

팩토리 메서드 패턴은 위와 같은 구조를 가집니다.

  • Product : Creator와 하위 클래스가 생성하는 모든 객체의 공통 인터페이스
  • Concreate Creator : 기본 팩토리 메서드를 오버라이드하여 구체적인 Product 객체를 생성함
  • Creator : 새로운 객체를 반환하는 팩토리 메서드를 선언. Product 인터페이스를 준수해야 함

 

팩토리 메서드 패턴 예시

Music Player, Video Player 예시를 통해 팩토리 메서드 패턴을 알아보겠습니다.

 

먼저 Product에 해당하는 Player 프로토콜(인터페이스)을 만들겠습니다.

//Product
protocol Player {
    var content: String { get set }
        
    func play()
    func pause()
}

 

Player는 Music Player와 Video Player가 공통으로 가지는 프로퍼티, 메서드를 정의합니다.

 

이 Product를 준수하는 Concrete Product를 만들겠습니다.

Concrete Product는 실제 사용할 객체를 의미하고, Concreate Creator 생성할 객체이기도 합니다.

Concrete Product는 Product를 준수해야 합니다.

// Concrete Product
struct MusicPlayer: Player {
    var content: String
    
    func play() {
        print("[MusicPlayer] Play \(content)")
    }
    
    func pause() {
        print("[MusicPlayer] Pause")
    }
}

// Concrete Product
struct VideoPlayer: Player {
    var content: String
    
    func play() {
        print("[VideoPlayer] Play \(content)")
    }
    
    func pause() {
        print("[VideoPlayer] Pause")
    }
}

Player를 준수하는 MusicPlayer와 VideoPlayer를 생성했습니다.

 

이제 Creator를 구현해 봅시다.

Creator에서는 팩토리 객체가 채택할 인터페이스를 정의합니다.

// Creator
protocol PlayerCreator {
    func createPlayer(content: String, contentType: ContentType) -> Player
}

enum ContentType {
    case music
    case video
}

Player를 생성하는 createPlayer 메서드가 있습니다.

팩토리는 이 메서드를 구현해서 Concrete Product를 생성합니다.

 

마지막으로 Factory (Concrete Creator)를 구현합니다.

// Factory (Concrete Creator)
final class PlayerFactory: PlayerCreator {
    func createPlayer(content: String, contentType: ContentType) -> Player {
        switch contentType {
        case .music:
            return MusicPlayer(content: content)
        case .video:
            return VideoPlayer(content: content)
        }
    }
}

PlayerFactory는 Product 타입을 반환합니다.

Swift는 Protocol 타입을 반환할 수 있기 때문에 Concrete Product를 생성하고 Product 타입으로 반환합니다.

 

이를 실행한 결과입니다.

let playerFactory = PlayerFactory()

let musicPlayer = playerFactory.createPlayer(content: "차이콥스키 바이올린 협주곡 D단조", contentType: .music)
let videoPlayer = playerFactory.createPlayer(content: "타이타닉", contentType: .video)

musicPlayer.play() //[MusicPlayer] Play 차이콥스키 바이올린 협주곡 D단조
musicPlayer.pause() //[MusicPlayer] Pause

videoPlayer.play() //[VideoPlayer] Play 타이타닉
videoPlayer.pause() //[VideoPlayer] Pause

 

감사합니다.

 

참고

https://icksw.tistory.com/237

https://icksw.tistory.com/235

https://jeonyeohun.tistory.com/386

https://jusungpark.tistory.com/14

https://cjw-awdsd.tistory.com/54

https://velog.io/@ellyheetov/Factory-Pattern

 

반응형