Abstract Factory

DongHeon·2022년 11월 4일
0

디자인 패턴

목록 보기
3/12

Factory Method에 이어 Abstract Factory에 대해 알아보겠습니다.
이름처럼 두 패턴은 비슷한 점도 있지만 분명히 다른 점도 존재합니다.

Abstract Factory?

서로 관련있는 객체를 만들어주는 패턴을 말합니다.

위에서도 언급했듯이 두 패턴은 결국 객체를 만들어 준다는 공통점이 존재하지만 Abstract Factory같은 경우 구체적으로 어떤 객체를 사용하는지에 대해 숨길 수 있습니다.


UML을 보면 Client는 구체적인 타입이 아닌 추상화된 프로토콜을 사용합니다.

코드

지난번에 작성한 Factory Method를 가져오겠습니다.

패턴 적용 전

class Car {
    var name: String
    var color: String
    var tire: Tire
    
    init(name: String, color: String, tire: Tire) {
        self.name = name
        self.color = color
        self.tire = tire
    }
}

class Tire { 
	... 
}

CarTire라는 타입을 가지는 프로퍼티가 추가됐습니다.

그럼 기존에 만들어 놓은 Factory는 어떻게 변하는지 확인해 보겠습니다.

class K3Factory: Factory {
    func makeCar(color: String) -> Car {
        return K3(name: "K3", color: color, tire: Tire())
    }
}

만약 제가 일반 Tire가 아닌 새로운 Tire를 만들어 사용하고 싶다면 어떻게 해야 할까요?

class NewTire { 
	... 
}

class Car {
    var name: String
    var color: String
    var tire: NewTire
    
    init(name: String, color: String, tire: NewTire) {
        self.name = name
        self.color = color
        self.tire = tire
    }
}

class K3Factory: Factory {
    func makeCar(color: String) -> Car {
        return K3(name: "K3", color: color, tire: NewTire())
    }
}

이처럼 기존의 코드를 변경해야 하는 불편함이 존재합니다.

패턴 적용

  • AbstractFactory
protocol CarPartFactory {
    func createTire() -> Tire
}
  • ConcreteFactory
class NormalTireFactory: CarPartFactory {
    func createTire() -> Tire {
        return NormalTire()
    }
}
  • ProductA & ConcreteProductA
protocol Tire { 
	... 
}

class NormalTire: Tire { 
	... 
}

패턴 적용 전에는 Tire를 클래스로 만들었지만 프로토콜로 수정했습니다.

  • Client
class K3Factory: Factory {
    let partFactory: CarPartFactory
    
    init(partFactory: CarPartFactory) {
        self.partFactory = partFactory
    }
    
    func makeCar(color: String) -> Car {
        return K3(name: "K3", color: color, tire: partFactory.createTire())
    }
}

let normalFactory = NormalTireFactory()
let myCar = K3Factory(partFactory: normalFactory).orederCar(color: "White")

여기서는 각 부품에 대한 Abstract Factory를 결국 Factory에서 사용하기 때문에 위 코드처럼 작성했습니다.

여기서 NewTire를 사용하는 K3를 만들어 보겠습니다.

class NewTire: Tire { 
	... 
}

class NewTireFactory: CarPartFactory {
    func createTire() -> Tire {
        return NewTire()
    }
}

let newFactory = NewTireFactory()
let secondCar = K3Factory(partFactory: newFactory).orederCar(color: "Black")

K3Factory에 작성한 코드를 수정하지 않고 NewTire 사용하는 새로운 인스턴스를 생성할 수 있습니다.

이처럼 Abstract Factory를 사용하면 Client의 코드를 수정하지 않고 다른 타입을 가지고 있는 인스턴스를 생성할 수 있습니다.

장단점

  • 장점
  1. 구체적인 타입들과 Client 사이의 결합도를 낮출 수 있다.
    (추상화를 통해 구체적인 타입이 아닌 추상 타입에 의존하기 때문이다.)
  2. 기존 Client 코드를 수정하기 않고 다른 타입을 가지는 인스턴스를 생성할 수 있다.
  • 단점
  1. Factory Method와 마찬가지로 관리해야 하는 객체들이 증가해 복잡하다.

해당 글은 인프런의 코딩으로 학습하는 GoF 디자인 패턴 강의와 블로그를 참고해 작성했습니다.

참고 블로그
Refactoring.Guru

⭐️ 부족하거나 잘못된 부분이 있다면 댓글은 언제나 환영입니다!! ⭐️

0개의 댓글