Factory Pattern

pcsoyeon·2021년 11월 24일
0

Factory Pattern은 디자인 패턴의 생성 패턴 중 하나이다.

Creational Pattern : 디자인 패턴 중 생성 패턴으로 Factory Pattern을 포함하고 있다. 해당 패턴은 객체 생성의 복잡도를 낮추는 패턴들을 다룬다. 

이름을 통해서 알 수 있는 것처럼 우리가 어떤 제품을 공장에 요청할 때 공장에서는 어떤 요구가 들어오는지 처음부터 알 수 없다. 즉, 공장에서는 제품을 만들지만 요청에 따라서 A 제품이 나올 수도 있고 B 제품이 나올 수도 있다. 그렇다고 해서 공장의 생산 라인이 달라지지는 않는다. 제품이 달라질 뿐이다.

팩토리 패턴은 자주 사용하는 프로그램의 뼈대를 만들 때 사용되기도 한다. 템플릿 메서드 패턴과 함께 사용하면 보다 효과적으로 프로그램의 뼈대를 정의할 수 있다.

사용자에게 객체 생성 로직을 숨긴채 객체를 생성하기 때문에 사용자는 필요한 객체의 생성 로직을 신경쓰지 않고 특정 객체를 가져올 수 있다.

이를 실제 프로젝트 상황 속에서 설명하면 다음과 같다.

예를 들어 사용자의 profile 정보를 보여주는 view가 있다고 가정해보자. 해당 profile view에서 보여주는 기본적인 정보는 사용자의 이름, 나이, 프로필 이미지, 닉네임 등이 있을 수 있다. 그리고 상황에 따라 크리스마스일 때 보여지는 UI가 달라질 수 있고 premium 유저의 경우 일반 유저와 다른 UI로 profile view가 구성될 수 있다. 그렇다고 해서 앞서 말한 이름, 나이와 같은 기본적인 정보가 달라지는 것은 아니다.

Factory Pattern

The factory pattern is a way to encapsulate the implementation details of creating objects, which adheres to a common base class or interface.

객체를 만들기 위한 인터페이스를 정의하지만 어떤 클래스의 인스턴스를 생성할지에 대한 결정은 하위 클래스가 정하도록 하는 방법이다. 서브 클래스가 객체를 생성하도록 처리하는 디자인 패턴이다.

팩토리 패턴을 사용하면 객체 생성을 캡슐화 할 수 있으며 부모 클래스는 자식 클래스가 어던 객체를 생성하는지 모른다. 객체 생성을 전담하는 struct/class를 만들어서 구체적인 생성 과정을 그 안에서 구현한다. (즉, 객체 생성을 다른 struct/class가 전담한다.)

Factory Pattern의 목적

  • 객체 생성을 위한 복잡한 과정을 없앨 수 있다.
    (사실상 없애는 것이 아니라 겉으로 드러나지 않도록 캡슐화하여 사용하도록 하는 것이다.)
  • 객체 생성의 구체적인 구현을 generic하게 객체를 사용하여 분리한다.
    (제너릭 타입이 타입에 유연성을 제공해서 컴포넌트 등을 재사용 가능하게 하는 것처럼 객체 생성의 유연성을 부여하는 것)

Factory Pattern을 사용할 때

  • 생성할 객체의 클래스 종류를 예측할 수 없을 때
  • 만들어야 할 객체의 하위 클래스를 명시하고 싶을 때

종류

  • Factory Method Pattern
  • Abstract Factory Pattern

Factory Method Pattern

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

팩토리 메서드 패턴은 하나의 객체만 생산(단일 상품을 생산)한다.

Abstract Factory Pattern

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

관련된 상품을 여러개 생산한다.
단일 상품을 생산하는 여러개의 팩토리 메서드를 가진 abstract factory로 상품들은 서로 관련된 family이다.

관련된 객체들은 한번에 캡슐화하여 팩토리로 만들어서 일관되게 객체를 생성하도록 한다.
팩토리 메서드가 여러개이고 관련된 객체들을 각각 만든다.(make)

공통점 및 차이점

공통점

  • 구조 : Factory, Product가 필요하다.
    - Factory(Creator) : 객체의 종류를 판단하고 생성한다.
    - Product : Factory에서 생성되는 객체의 공통 조상으로 Factory에서 생성되는 객체를 product를 상속받거나 채택한 타입이다.
  • 생성은 Factory에서 맡아서 한다. (Factory Method에서 객체 생성을 담당한다.)
    - Factory Method 인자에 따라서 생성되는 객체가 결정된다.
  • 실제 구현 대상인 concreate class/struct와 client 간의 결합도를 낮춘다.

차이점

  • 생성 범위 :
    - Factory Method : 하나의 팩토리에서 하나의 make()
    - Abstract Factory : 하나의 팩토리에 연관된 여러 종류의 make()
  • 객체 종류 결정 :
    - Factory Method : 인자에 따라 객체 종류가 결정
    - Abstract Factory : 인자에 따라 객체 생성을 담당하는 Factory 종류가 결정
  • 결합도 낮추는 대상
    - Factory Method : Concrete Product, Client
    - Abstract Factory : Concrete Factory, Client
  • Focus
    - Factory Method : Factory Method 레벨에 집중
    - Abstract Factory : Abstract Factory 레벨에 집중
  • 추상화 정도
    - Factory Method : method
    - Abstract Factory : class

Design Pattern

Design patterns are blueprints which outline the best practices that create re-usable object oriented code, solving common software problems.

  • 디자인 패턴은 소프트웨어 문제들을 해결하기 위한 대표적인 해결 방안 (그 중에서 좋은 것들) 의 모음
  • 소프트웨어 디자인 패턴은 크게 4가지로 구분
  1. Creational Patterns
  2. Structural Patterns
  3. Behavioural Patterns
  4. Concurrency Patterns

Factory Pattern in Swift

  • Protocol 사용 : Product 공통 조상을 type으로 사용
  • Naming : swift api guideline에 따르며 팩토리 메서드 이름을 make로 시작해야 한다.

Example

Product

// MARK: - Shose Product

protocol Shose {
    func getName()
}

class NikeShose: Shose {
    func getName() {
        print("Nike Shose")
    }
}

class AddidasShose: Shose {
    func getName() {
        print("Addidas Shose")
    }
}

// MARK: - T Shirt Product

protocol Tshirt{
    func getName()
}

class NikeTshirt: Tshirt {
    func getName() {
        print("Nike T-Shirt")
    }
}

class AddidasTshirt: Tshirt {
    func getName()  {
        print("Addidas T-Shirt")
    }
}

Factory

enum BrandType {
    case nike
    case addidas
}

protocol ShoseFactory {
    func makeShose(brand: BrandType)
}

class BrandShoseFactory: ShoseFactory {
    func makeShose(brand: BrandType){
        switch brand {
        case .nike:
            return NikeShose().getName()
        case .addidas:
            return AddidasShose().getName()
        }
    }
}


protocol TshirtFactory {
    func makeTshirt(brand: BrandType)
}

class BrandTshirtFactory: TshirtFactory {
    func makeTshirt(brand: BrandType) {
        switch brand {
        case .nike:
            return NikeTshirt().getName()
        case .addidas:
            return AddidasTshirt().getName()
        }
    }
}

Concrete Factory

class SportswareFactory {
    func makeSportsware(brand: BrandType) {
        let shoseFactory = BrandShoseFactory()
        let tshirtFactory = BrandTshirtFactory()
        
        shoseFactory.makeShose(brand: brand)
        tshirtFactory.makeTshirt(brand: brand)
    }
}

Concrete Client

class Client {
    init(brand: BrandType) {
        let client = SportswareFactory()
        client.makeSportsware(brand: brand)
    }
}
profile
Slowly But Surely

0개의 댓글