- 팩토리 패턴2025년 03월 25일
- 2료일
- 작성자
- 2025.03.25.오후06:11
객체 생성을 캡슐화하는 생성 패턴중 하나이다. 객체를 직접 생성하는 대신, 팩토리라는 중간 객체를 통해 생성한다. 이렇게 되면 코드의 유연성이 높아지고, 객체 생성 로직을 한 곳에서 관리할 수 있어 유지보수가 쉬워진다.
팩토리 메서드 패턴
언제쓰지?
1. 단일 제품의 다양한 변형을 생성할 때
2 어떻게 하나의 객체를 생성할 것인가에 초점을 맞춘다.
ex) iOS 앱에서 배송 관리 앱을 만든다고 가정해봅시다. 처음에는 트럭(Truck)만 지원했기 때문에 모든 코드가 Truck클래스에 의존적입니다. 그런데 갑자기 배송 업체에서 "배(Ship)"도 지원해달라는 요청이 들어왔습니다.
- 기존 코드: let transport = Truck()처럼 직접 생성.
- 문제: Ship을 추가하려면 클라이언트 코드 전체를 수정해야 하고, 나중에 또 다른 운송 수단(예: 비행기)이 추가되면 계속 반복됩니다. 조건문(if-else)이 난무하게 되죠
그래서 클라이언트는 구체적인 클래스(Truck, ship)을 알필요 없이 추상화된 인터페이스만 사용하는 팩토리 메서드 패턴을 적용해보자.
// Product 인터페이스 protocol Transport { func deliver() -> String } // Concrete Product class Truck: Transport { func deliver() -> String { return "Delivering by land with a truck" } } class Ship: Transport { func deliver() -> String { return "Delivering by sea with a ship" } } // Creator protocol Logistics { func createTransport() -> Transport // 팩토리 메서드 func planDelivery() -> String } extension Logistics { func planDelivery() -> String { let transport = createTransport() return transport.deliver() } } // Concrete Creator class RoadLogistics: Logistics { func createTransport() -> Transport { return Truck() } } class SeaLogistics: Logistics { func createTransport() -> Transport { return Ship() } } // 클라이언트 코드 func clientCode(logistics: Logistics) { print(logistics.planDelivery()) } let road = RoadLogistics() let sea = SeaLogistics() clientCode(logistics: road) // 출력: Delivering by land with a truck clientCode(logistics: sea) // 출력: Delivering by sea with a ship
Product 인터페이스: TransPort 팩토리 메서드가 생성하는 객체들이 구현해야 하는 공통 인터페이스
Concrete Products(트럭, 배): TransPort인터페이스를 구체적으로 구현한 클래스들
Creator(Logisitcs 프로토콜): 객체 생성을 위한 팩토리 메서드(createTransPort)를 선언하고, 이 메서드를 사용하는 기본 비즈니스 로직 포함
Concrete Creators(RoadLogistics, seaLogistics): Logistics 프로토콜을 구현하여 팩토리 메서드를 오버라이드하고 자신만의 제품 유형을 반환
장점 : 결합도 감소(클라이언트와 구체적인 클래스가 분리), SRP(객체 생성 로직을 한 곳에 모아 관리하기 쉬워진다), OCP( 새로운 운송 수단을 추가하려면 새 서브클래스만 만들면된다)
추상 팩토리 패턴
: 구체적인 클래스를 지정하지 않고도 관련된 객체의 집합을 생성해주는 생성 디자인 패턴
관련된 객체들의 집합을 생성하는데 중점을 둔다.
- 어떻게 호환되는 객체 군을 생성할 것인가에 초점
ex) 가구 쇼핑앱을 만든다고 생각해보자. 앱에서 의자, 소파, 테이블을 판매하는데 이 가구들은 스타일에 따라 다르게 제공된다. 고객은 같은 스타일로 맞춘 가구 세트를 원한다. 이때 추상 팩토리 패턴을 사용하면 스타일별로 일관된 가구 집합을 쉽게 생성할 수 있어진다.
구성요소
1. Abstract Product: 관련된 제품군의 인터페이스(Chair, Sofa)
2. Concrete Product: 각변형에 따른 구체적인 구현(ModernChair, VictorianChair)
3. Abstract Factory: 모든 제품을 생성하는 메서드 집합을 정의한 인터페이스(FurnitureFactory)
4. Concrete Factory: 특정 변형에 맞는 제품을 생성하는 구현체(ModernFurnitureFactory)
5. Client: 추상팩토리와 제품 인터페이스를 사용하는 코드
// Abstract Product protocol Chair { func sitOn() -> String } protocol Sofa { func lieOn() -> String } // Concrete Product class ModernChair: Chair { func sitOn() -> String { return "Sitting on a sleek modern chair" } } class ModernSofa: Sofa { func lieOn() -> String { return "Lying on a comfy modern sofa" } } class VictorianChair: Chair { func sitOn() -> String { return "Sitting on an ornate Victorian chair" } } class VictorianSofa: Sofa { func lieOn() -> String { return "Lying on a luxurious Victorian sofa" } } // Abstract Factory protocol FurnitureFactory { func createChair() -> Chair func createSofa() -> Sofa } // Concrete Factory class ModernFurnitureFactory: FurnitureFactory { func createChair() -> Chair { return ModernChair() } func createSofa() -> Sofa { return ModernSofa() } } class VictorianFurnitureFactory: FurnitureFactory { func createChair() -> Chair { return VictorianChair() } func createSofa() -> Sofa { return VictorianSofa() } } // Client 코드 class FurnitureShop { private let factory: FurnitureFactory init(factory: FurnitureFactory) { self.factory = factory } func setupRoom() -> String { let chair = factory.createChair() let sofa = factory.createSofa() return "\(chair.sitOn()) and \(sofa.lieOn())" } } // 사용 예시 let modernShop = FurnitureShop(factory: ModernFurnitureFactory()) print(modernShop.setupRoom()) // 출력: Sitting on a sleek modern chair and Lying on a comfy modern sofa let victorianShop = FurnitureShop(factory: VictorianFurnitureFactory()) print(victorianShop.setupRoom()) // 출력: Sitting on an ornate Victorian chair and Lying on a luxurious Victorian sofa
팩토리메서드와 추상팩토리 차이
팩토리 메서드가 단일 객체 생성에 초점을 맞췄다면, 추상팩토리는 객체 집합을 다룬다.
// Abstract Product protocol Button { func render() -> UIButton } protocol Label { func render() -> UILabel } // Concrete Product class DarkButton: Button { func render() -> UIButton { let button = UIButton() button.backgroundColor = .black button.setTitleColor(.white, for: .normal) return button } } class DarkLabel: Label { func render() -> UILabel { let label = UILabel() label.textColor = .white label.backgroundColor = .black return label } } class LightButton: Button { func render() -> UIButton { let button = UIButton() button.backgroundColor = .white button.setTitleColor(.black, for: .normal) return button } } class LightLabel: Label { func render() -> UILabel { let label = UILabel() label.textColor = .black label.backgroundColor = .white return label } } // Abstract Factory protocol ThemeFactory { func createButton() -> Button func createLabel() -> Label } // Concrete Factory class DarkThemeFactory: ThemeFactory { func createButton() -> Button { return DarkButton() } func createLabel() -> Label { return DarkLabel() } } class LightThemeFactory: ThemeFactory { func createButton() -> Button { return LightButton() } func createLabel() -> Label { return LightLabel() } } // Client (UIViewController) class ThemeViewController: UIViewController { private let factory: ThemeFactory init(factory: ThemeFactory) { self.factory = factory super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() setupUI() } private func setupUI() { let button = factory.createButton().render() let label = factory.createLabel().render() button.frame = CGRect(x: 50, y: 100, width: 200, height: 50) label.frame = CGRect(x: 50, y: 160, width: 200, height: 30) label.text = "Hello, Theme!" view.addSubview(button) view.addSubview(label) } } // 사용 예시 let darkVC = ThemeViewController(factory: DarkThemeFactory()) let lightVC = ThemeViewController(factory: LightThemeFactory())
참고자료
https://refactoring.guru/design-patterns/factory-method
Factory Method
/ Design Patterns / Creational Patterns Factory Method Also known as: Virtual Constructor Intent Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objec
refactoring.guru
https://refactoring.guru/design-patterns/factory-method
'디자인패턴' 카테고리의 다른 글
파사드 패턴(Facade Pattern) (0) 2025.03.25 Adaptor Pattern (구조적 디자인패턴) (0) 2025.03.24 다음글이전글이전 글이 없습니다.댓글