Factory Method Pattern
Factory 패턴은 객체를 생성하는 모듈인 'Factory'를 만들어놓고 요청에 따라 객체를 생성하는 패턴입니다.
Factory Method 패턴은 어떤 객체의 인스턴스를 생성할지 서브 클래스에서 결정하도록 합니다. 객체 생성을 처리하는 팩토리를 프로토콜로 관리하여 실질적인 생성을 캡슐화하는 것이 가능합니다.
일반적으로 Creator, Concrete Creater, Product, Concrete Product로 구성됩니다. Creator에서는 추상적 정보만 파악하고 있고, Concrete Creator에서 객체 생성에 대한 결정을 수행합니다.
아래는 간단한 구현예시입니다.
// Product
protocol Product {
func hello()
}
- Product : 생성되는 객체에 대한 동작을 정의합니다.
// Concrete Product
class A: Product {
func hello() {
print("Hello, Im A")
}
}
class B: Product {
func hello() {
print("Hello, Im B")
}
}
- Concrete Product : Product에 대한 구체타입입니다.
// Creator
protocol Factory {
func createProduct() -> Product
}
- Creator : Facotry의 역할을 정의합니다.
- 여기서 createProduct 메서드가 위 그림의 factoryMethod에 해당합니다.
// Concrete Creator
class AFactory: Factory {
func createProduct() -> Product {
return A()
}
}
class BFactory: Factory {
func createProduct() -> Product {
return B()
}
}
- Concrete Creator : Facotry에 대한 구체 타입입니다.
- 여기서 createProduct 메서드가 위 그림의 factoryMethod에 해당합니다.
- 예시에서는 두 개의 Factory를 나누어 표현했지만 두 Factory는 합쳐질 수 있습니다. (하나의 공장에서 하나의 추상타입에 대한 여러 구체타입에 객체 생성가능, 파라미터를 받아 타입을 구분하여 객체를 반환)
class Client {
func order(factory: Factory) {
let elctronicsProduct = factory.createProduct()
elctronicsProduct.hello()
}
}
var client = Client()
client.order(factory: AFactory()) // Hello, Im A
client.order(factory: BFactory()) // Hello, Im B
- Client는 Factory를 활용해 Product를 생성하고 활용합니다.
Factory Method Pattern의 사용 이유 및 단점
그냥 클라이언트쪽에서 직접 Concrete Product를 생성해도 될 텐데 왜 굳이 이렇게 할까요?
새로운 객체가 생기거나 객체에 대한 수정이 생겨도, 클라이언트가 아닌 Factory만 수정하면 되기 때문에 코드 간 결합성을 낮출 수 있기 때문입니다. 이는 코드 사용에 강력한 유연성을 제공합니다.
클라이언트는 자신이 필요로 하는 인스턴스(Product)에 대한 구체타입을 파악하고 있지 않습니다. 프로토콜(인터페이스)를 통해 필요한 기능만을 파악하고 있을 뿐입니다. 심지어 이를 생성해주는 공장(Creator)의 구체타입도 모릅니다. 이 역시 프로토콜(인터페이스)를 통해서 '이 인스턴스는 내가 필요로 하는 인스턴스를 만들어줄 수 있구나' 정도만 알고 있는 상황입니다.
만약 클라이언트가 모든 구체타입을 알고 있는 구조라면, 구체타입의 수정이 발생할 때 이를 반영하기 위해 해당 구체타입을 사용하는 모든 곳에서 해당 수정사항을 적용해야 할 것입니다. 하지만 지금처럼 클라이언트들이 기능에 대한 프로토콜(인터페이스)만을 파악하고 있다면 Creator에 수정사항을 반영하기만 하면 됩니다. 필요한 코드 수정사항이 훨씬 줄어드는 것이죠.
이러한 장점은 객체지향 설계의 SOLID 원칙 중 OCP(개방 폐쇄 원칙, 확장에 대해 열려 있어야 하고 수정에 대해서는 닫혀 있어야 한다)와도 관련이 깊습니다. 클라이언트는 프로토콜(인터페이스)를 통해 필요한 기능만을 파악해 수정을 방지했으며, 해당 기능을 구현한 구체 타입의 확장 가능성은 열어둔 구조니까요.
다만 해당 프로토콜을 따르는 구체 타입을 필요로 할 때마다 해당 사항을 팩토리에 반영해주어야 하고, 구체 타입이 너무 많아질 경우 오히려 관리가 어려워질 수 있다는 단점이 존재합니다. 그러니까 너무 남발하여 사용하는 것은 좋지 못하겠죠?
'🍎 Apple > Patterns' 카테고리의 다른 글
[iOS Design Pattern] Decorator (0) | 2022.05.18 |
---|---|
[iOS Design Pattern] Coordinator (3) | 2022.04.12 |
[iOS Architecture] VIPER (0) | 2022.04.11 |
[iOS Architecture] MVC, MVP, MVVM (feat. Clean Architecture) (4) | 2022.01.30 |
Clean Architecture and Design - Robert C. Martin (엉클 밥) (2) | 2022.01.21 |