팩토리 패턴
팩토리 패턴은 팩토리 객체를 이용해 객체 생성 관심사를 분리하는 디자인 패턴입니다.
팩토리 메서드 패턴과 추상 팩토리 패턴으로 나뉘며 Swift에서는 프로토콜로 구현할 수 있습니다.
팩토리 패턴이 나오게 된 배경은 OCP(개방 폐쇄 원칙)와 연결지어 설명할 수 있습니다.
OCP는 확장에는 열려 있지만 변경에는 닫혀 있어야 한다는 원칙인데요.
닫혀 있어야 한다는 것은 확장을 했을 때 다른 부분에 영향을 주지 않아야 한다는 것을 의미합니다. (예시는 여기)
객체 생성 관심사를 분리해서 객체의 속성, 함수 등이 변경될 때 수정이 발생하는 범위를 최소화할 수 있습니다.
팩토리 메서드 패턴
팩토리 메서드 패턴은 인터페이스로 객체 생성 팩토리를 제공하고, 객체 생성 결정은 하위 클래스가 정하는 패턴입니다.
객체 생성을 캡슐화할 수 있으며 부모 클래스는 자식 클래스가 어떤 객체를 생성하는지 몰라도 됩니다.
(클래스라고 말하고 있지만 Swift는 프로토콜을 채택한 구조체도 포함합니다.)
팩토리 메서드 패턴은 위와 같은 구조를 가집니다.
- 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://jeonyeohun.tistory.com/386
https://jusungpark.tistory.com/14
https://cjw-awdsd.tistory.com/54
https://velog.io/@ellyheetov/Factory-Pattern