[Design Pattern] 팩토리 패턴 - 팩토리 메소드 패턴과 추상 팩토리 패턴

nnnyeong·2021년 7월 25일
0

DesignPattern

목록 보기
9/9
post-thumbnail

팩토리 패턴에 대해 알아보자!

팩토리 패턴

팩토리 패턴은 객체의 생성을 캡슐화 하는 패턴이다.
구체적인 객체의 생성 과정을 '팩토리'로 모듈화 하여 구체적인 부분이 아닌 추상적인 부분에 의존할 수 있도록 한다.

팩토리 패턴에는 팩토리 메소드 패턴과 추상 팩토리 패턴이 있다!




팩토리 메소드 패턴

팩토리 메소드 패턴은 객체를 생성하기 위한 인터페이스를 정의하고 어떤 구체적인 클래스의 인스턴스를 생성할지는 서브클래스가 결정하도록 한다.
객체를 생성하여 반환하는 메소드 (= 팩토리 메소드) 는 구체적인 객체를 반환한다.

피자 가게를 상상해보자. 다양한 피자들의 주문이 들어올 수 있다. 뉴욕피자, 시카고피자, 이탈리안피자 등등~ 주문이 들어온 피자를 반환하는 과정을 코드로 나타내면 자연스레 if-else 문이 떠오를 것이다



    if type == "NewYork" {
        return NewYorkPizza()
    }else if type == "Chicago"{
        return ChicagoPizza()
    }else{
        return ItalianPizza()
    }


만약 새로운 코리안 피자가 등장한다면? 갑자기 NewYorkPizza의 판매가 중단된다면?

이러한 경우 여러 변동사항들에 쉽게 대처할 수 없다
매번 if-else 문을 추가하고, 변경하고,,

다양한 변화에 보다 유연하게 대응하기 위해 피자 생성 과정을 팩토리로 분리하여 보자!

UML

구체적 클래스인 NewYorkCheesePizza, ChicagoCheesePizza 등은 상위 클래스인 Pizza 를 상속하여 동일하게 Pizza 로 다룰 수 있도록 하고,

이러한 구체적인 클래스를 생성하는 과정을 PizzaStore 로 분리하여 client는 구체적으로 NewYork 피자를 생성하는지, ChicagoPizz를 생성하는지 관여하지 않아도 되도록 한다!

코드로 살펴보면,

코드

class PizzaStore {
    func createPizza(type : String) -> Pizza {}
}

class NewYorkStore : PizzaStore {
    override func createPizza(type : String)-> Pizza {
        if type == "Cheese" {
            return NewYorkCheesePizza()
        }else{
            return NewYorkVeggiePizza()
        }
    }
}

class ChicagoStore : PizzaStore {
    override func createPizza(type: String) -> Pizza {
        if type == "Cheese" {
            return ChicagoCheesePizza()
        }else{
            return ChicagoVeggiePizza()
        }
    }
}

구체적인 하위 클래스를 결정하는 부분을 PizzaStore 로 캡슐화 하였다

이후 클라이언트는,

var store = PizzaStore()
let nyCheesePizza = store.createPizza(type: "Cheese")

store = ChicagoStore()
let chicagoViggiePizza = store.createPizza(type: "Veggie")

구체적인 피자를 결정하고 생성하는 팩토리를 통해서 인스턴스를 생성해 전달 받을 수 있다!

슈퍼클래스에서 사용할 객체의 타입을 서브클래스의 팩토리에서 결정하고, 슈퍼클래스에서는 클라이언트의 요청을 받아 처리만 할 뿐, 구체적인 구현체를 알지 않아도 된다!

팩토리 메소드 패턴을 사용하여

  • 객체 생성의 역할을 명확히 구분하고
  • 객체 생성을 한 곳에 모아두어 관리하고 가독성을 높일 수 있다
  • 상위 클래스는 추상체에만 의존하는 구조로 코드의 확장성, 유연성을 높이게 된다!



추상 팩토리 패턴

그렇다면 추상 팩토리 패턴은 무엇일까?
이름도 비슷한 팩토리 메소드 패턴과 추상 팩토리 패턴 중 추상 팩토리 패턴의 용도는 연관된 객체들의 집합군을 생성하는 패턴이라는 것이다!

클라이언트는 추상팩토리 인터페이스를 통해서 일련의 객체군을 공급받게 되는 구조를 가진다!

유사한 피자 사례로 알아보자

UML

NewYorkCheesePizza, ChicagoVeggiePizza 등등 각 피자에 들어가는 다양한 재료의 조합이 다를 것이다. 이 때 복잡한 if-else 문을 통해 매번 필요한 재료들을 생성하지 않고 각 재료들의 집합군을 생성하는 추상팩토리 객체를 통해 이를 해결한 모습이다.

코드

class PizzaIngredientFactory {
    func createSauce(type : String) -> Sauce {}
    func createCheese(type : String) -> Cheese {}
}

class NewYorkIngredientFactory : PizzaIngredientFactory {
    override func createSauce(type : String) -> Sauce {
        if type == "Cheese" {
            return TomatoSauce()
        }else{
            return BBQSauce()
        }
    }
    
    override createCheese(type : String) -> Cheese {
        if type == "Cheese" {
            return AmericanCheese()
        }else{
            return MozzarellaCheese()
        }
    }
}

추상 팩토리 인스턴스 NewYorkIngredientFactory, ChicagoIngredientFactory 는 피자에 필요한 재료 (치즈, 소스) 등을 각 피자에 맞는 조합으로 생성하여 반환한다.

추상 팩토리 패턴을 사용하여

  • 연관된 객체를 여러곳에서가 아닌 한 곳에서 생성하여 일관성을 높이고
  • 구체적 클래스들을 고립시킬 수 있다



팩토리 메소드 & 추상 팩토리

  • 팩토리 메소드 패턴을 상속을 통해 서브 클래스에서 팩토리 메소드를 오버라이딩하여 객체의 생성부를 구현한다
  • 추상 팩토리 패턴은 객체의 집합을 생성하기 위한 정의를 추상체에 위치시키고 하위의 구현체에서 세부적인 집합 생성 과정을 구현한다. 응집화된 객체군을 생성하려 할 때 추상 팩토리 패턴을 사용할 수 있다
  • 팩토리 메소드 패턴과 추상 팩토리 패턴 모두 객체의 생성부를 캡슐화하여 결합을 낮추고 구체적인 타입에 의존하지 않도록 할 수 있다!
profile
주니어 개발자까지 ☄️☄️

0개의 댓글