본문 바로가기
Programming/OOP

[Design Pattern] Abstract Factory Pattern, 추상 팩토리 패턴

by TinKerBellBass 2022. 4. 29.
728x90
반응형

팩토리 메서드 패턴이 제품을 생산하기 위한 것이라면

추상 팩토리 패턴은 제품을 구성하는 부품? 재료? 를 생산하기 위한 것이다.

 

 

[Design Pattern] Factory Method Pattern, 팩토리 메서드 패턴

DIP(Dependency Inversion Principle), 의존성 역전 원칙 변경에 강한 설계를 하기 위한 방법 중 잘 알려진 SOLID 원칙의 하나로 의존 흐름을 역전시키는 방법으로, 육각형 아키텍처의 포트-어댑터도 이 방법

tinkerbellbass.tistory.com

 

Abstract Factory Pattern

제품을 구성하는 부품들 중 연관이 있는 것을 묶어 생산하는 것이 추상 팩토리 패턴의 핵심이다.

구체적으로는 제품을 구성하는 부품을 만드는 인터페이스를 정의하고

그 인터페이스에 따라 다양한 부품군을 생산하는 것이다.

interface VehiclePartFactory {
    Engine createEngine();
    Tire createtire();
    List<Option> createOptions();
}

class CityVehiclePartFactory implements VehiclePartFactory {...}
class OffloadVehiclePartFactory implements VehiclePartFactory {...}

엔진, 타이어, 옵션들은 차량을 구성하는 부품으로 묶은 VehiclePartFactory 를 인터페이스로 정의하였고,

도심에 어울리는 차량의 부품을 생산하는 CityVehiclePartFactory

오프로드에 어울리는 차량의 부품을 생산하는 OffloadVehiclePartFactory

를 구현하였다.

 

이렇게 만들어진 부품 공장은 제품(차량)을 만들 때 의존성 주입을 통해 사용된다.

class SuperBus extends Vehicle {
	private VehiclePartFactory vehiclePartFactory
    
	public SuperBus(VehiclePartFactory vehiclePartFactory) {
    	this.vehiclePartFactory = vehiclePartFactory
    }
    
    public void assemble() {
    	engine = vehiclePartFactory.createEngine()
        tire = vehiclePartFactory.createTire()
        options = List.of()
    }
}

SuperBus 를 도심용으로 생산하고 싶으면 CityVehiclePartFactory 를 주입하고

VehiclePartFactory 에서 생산하는 부품 중 사용할 부품만 가져와서 사용하면 된다.

위에서는 엔진과 타이어를 만들고 옵션이 없는 깡통 SuperBus 를 만들고 있다.

좀 귀찮은 부분이 모든 제품이 부품군 팩토리를 필드로 가져야 하는 것인데,

추상 클래스에 넣으면 해결 될 것 같으나 외부에 유출하고 싶지 않은 필드를 protected 로 만들어야 해서

캡슐화에 문제가 있다. 

 

제품을 생산하는 공장에서는 제품에 필요한 부품군을 주입해 주면 된다.

class SuperVehicleFactory extends VehicleFactory {
    protected Vehicle createVehicle(VehicleType vehicleType) {
        return switch (vehicleType) {
            case BUS -> new SuperBus(new CityVehiclePartFactory());
            case TRUCK -> new SuperTruck(new OffloadVehiclePartFactory());
        }
    }
}

 

Abstract Factory Pattern Class Diagram

제품의 부품군을 생성하는 곳이 추상 팩토리 패턴의 핵심이므로, 제품을 생성하는 팩토리 메서드 패턴 부분은 제외하였다.

제품의 인터페이스가 Vehicle, 제품의 구상 클래스가 SuperBus, SuperTruck, UltraBus, UltraTruck,

제품에 필요한 부품군 팩토리의 인터페이스가 VehiclePartFactory,

부품군 팩토리의 구상 클래스가 CityVehiclePartFactory, OffloadVehiclePartFactory 이다.

CityVehiclePartFactory 는 도심용 차량 부품을 생산하는 공장이고,

OffloadVehiclePartFactory 는 오프로드용 차량 부품을 생산하는 공장이다.

제품은 필요한 부품군 공장을 주입받아 부품 생산을 부품군 공장에게 위임해서 받아 쓴다.

SuperBus 를 도심용 차량으로 생산하고 싶으면 CityVehiclePartFactory 를 주입받아, 도심용 차량 부품 생산을 위임하면 된다.

전체 소스는 https://github.com/Jongwon-Hyun/design_pattern

Factory Method Pattern VS. Abstract Factory Pattern

팩토리 메서드 패턴과 추상 팩토리 패턴의 가장 큰 차이는 확장을 통해 객체를 만드는가, 구성을 통해 객체를 만드는 가이다.

팩토리 메서드 패턴은 추상 공장 클래스를 확장한 구상 공장에서 제품을 생산하고,

추상 팩토리 패턴은 구성을 통해 제품에 주입되어 부품을 생산한다.

 

그리고 추상 팩토리 패턴에는 팩토리 메서드 패턴도 사용되고 있는데

실제로 부품을 만드는 것을 구상 클래스에 위임하고 있는 것이다.

// Factory Method Pattern
abstract class ProductFactory {
	public abstract Product createProduct();
}

class AbcProducctFactory extends ProductFactory {
	public Product createProduct() {
    	return Product;
    }
}

// Abstract Factory Pattern
interfact PartFactory {
	Part createPart();
}

class AbcPartFactory {
	public Part createPart() {
    	return Part;
    }
}

class Product {
	private PartFactory partFactory;
    
    // 부품군 팩토리 주입
    public Product(PartFactory partFactory) {
    	this.partFactory = partFactory;
    }
    
    public assemble() {
    	part = partFactory.createPart();
    }
}
728x90
반응형

댓글