추상 팩토리 패턴이란?
- 서로 관련된 여러 객체를 만들어주는 인터페이스를 제공하고 이를 구현하는 패턴
- 관련이 깊은 여러 종류의 객체를 일관된 방식으로 생성하는 경우에 유용하다.
- 팩토리 메서드 패턴 과 굉장히 비슷하다.
- 팩토리 메서드 패턴 은 하나의 객체 생성을 어떻게 할까에 집중하는 반면, 추상 팩토리 패턴은 관련 있는 여러 객체를 묶어 여러 구체적 클래스에 의존하지 않는 것에 집중한다.
다이어그램으로 살펴보기

AbstractFactory는CreateProductA()와CreateProductB()라는 추상 메서드를 제공한다.ProductA와ProductB를 생성한다.- 구체적인 객체 생성 방법의 구현은 하위 클래스에게 맡긴다.
ConcreteFactory1과ConcreteFactory2는ProductA와ProductB객체를 생성할 구체적인 생성 코드를 가지고 있다.
현실 세계와의 비유: 자동차 공장
자동차라는 완제품에엔진과타이어는 반드시 필요하다.- 두 객체는 서로 관련이 깊다고 볼 수 있다.
- 두 부품이 모두 같은 회사의 공장에서 나온다.
- 두 부품외 다른 종류의 부품은 모든 차가 같은 것을 쓴다고 가정하자.
디자인 패턴이 적용되지 않은 코드 살펴보기
public class SonataPartsFactory {
public CVVLEngine createCVVLEngine() {
return new CVVLEngine();
}
public HankookTire createHankookTire() {
return new HankookTire();
}
}
public class K9PartsFactory {
public V8Engine createV8Engine() {
return new V8Engine();
}
public MichelinTire createMichelinTire() {
return new MichelinTire();
}
}
@AllArgsConstructor
@ToString
public class Car {
private final Engine engine;
private final Tire tire;
}
public class Client {
public static void main(String[] args) {
K9PartsFactory k9PartsFactory = new K9PartsFactory();
SonataPartsFactory sonataPartsFactory = new SonataPartsFactory();
// create k9 car parts.
V8Engine v8Engine = k9PartsFactory.createV8Engine();
MichelinTire michelinTire = k9PartsFactory.createMichelinTire();
System.out.println("k9 엔진 : " + v8Engine);
System.out.println("k9 타이어 : " + michelinTire);
System.out.println("k9 생산: " + new Car(v8Engine, michelinTire));
// create sonata car parts.
CVVLEngine cvvlEngine = sonataPartsFactory.createCVVLEngine();
HankookTire hankookTire = sonataPartsFactory.createHankookTire();
System.out.println("쏘나타 엔진 생산: " + cvvlEngine);
System.out.println("쏘나타 타이어 생산: " + hankookTire);
System.out.println("쏘나타 생산: " + new Car(cvvlEngine, hankookTire));
}
}Sonata와K9부품 공장의 구현 예제이다.- 자동차에 필요한 부품인 엔진과 타이어를 모두 구체적으로 생성하고 있다.
- 반환 타입과 메서드명이 모두 구체적이라서 생성 객체가 바뀌어야 하면 모든 코드도 같이 바뀌어야 한다.
...PartsFactory코드와 이를 가져다 쓰는Client코드가 같이 바뀌어야 한다.
디자인패턴 적용하기
- 추상 팩토리 패턴을 적용해보자.
추상 팩토리 만들기
public interface Engine {
}
public interface Tire {
}
public interface CarPartsFactory {
Engine createEngine();
Tire createTire();
}Sonata와K5를Car라는 단어로 추상화하여 추상 팩토리를 만들었다.CVVLEngine과HankookTire등도Engine과Tire로 추상화하였다.
- 추상 팩토리는 연관된 객체를 생성하는 추상 메서드를 가지고 있는 인터페이스이다.
- 자동차를 만드는데 필요한 부품을 모아놨으므로 코드의 응집도에도 좋다.
추상 팩토리 클라이언트 클래스 만들기
public class CarFactory {
private final CarPartsFactory carPartsFactory;
public CarFactory(CarPartsFactory carPartsFactory) {
this.carPartsFactory = carPartsFactory;
}
public Car createCar() {
return new Car(
carPartsFactory.createEngine(),
carPartsFactory.createTire()
);
}
}CarPartsFactory를 주입받아 사용하는 클래스이다.- 이 클래스는 어떤 엔진과 어떤 타이어를 가진 자동차를 만들더라도 절대 변할 일이 없다.
디자인 패턴이 적용되지 않았던 코드 개선하기
public class K9PartsFactory implements CarPartsFactory{
@Override
public Engine createEngine() {
return new V8Engine();
}
@Override
public Tire createTire() {
return new MichelinTire();
}
}
public class SonataPartsFactory implements CarPartsFactory {
@Override
public Engine createEngine() {
return new CVVLEngine();
}
@Override
public Tire createTire() {
return new HankookTire();
}
}CarPartsFactory인터페이스를 상속하도록 바뀌었다.- 추상 팩토리의 구현체이다.
클라이언트 코드 개선하기
public class Client {
public static void main(String[] args) {
CarFactory k9Factory = new CarFactory(new K9PartsFactory());
CarFactory sonataFactory = new CarFactory(new SonataPartsFactory());
System.out.println("K9 생산 : " + k9Factory.createCar());
System.out.println("Sonata 생산 : " + sonataFactory.createCar());
}
}CarFactory를 생성하고 부품 공장만 주입해주면, 자동차 공장을 만들 수 있게 되었다.- 앞으로 어떠한 새로운 차가 나오더라도
CarFactory클래스는 변할 일이 없다. - 새로운 차가 나온다면, 어떤 엔진을 사용하고 어떤 타이어를 사용하는지를 명시하는
CarPartsFactory를 상속한 구현 클래스를 만들어주기만 하면 된다.CarFactory나CarPartsFactory등을 수정할 필요가 없는 점은 변경에 닫혀있다고 볼 수 있다.- 새로운 차를 추가하기 쉽다는 점은 확장에 열려있다고 볼 수 있다.
- 다만,
CarPartsFactory는 관점에 따라 하나의 클래스에서 여러가지 일을 한다고 볼 수도 있다.EngineFactory,TireFactory등으로 더 나뉘어도 되긴 한다.
다이어그램 살펴보기

팩토리 메서드 패턴과 비교해보기
- 둘 다 객체를 만드는 과정을 추상화시킨 것이다.
- 둘은 관점이 다르다.
- 팩토리 메서드 패턴은
팩토리를 구현하는 방법(inheritance)에 초점을 둔다.- 하나의 팩토리 메서드를 어떻게 구현할 것인가?
- 추상 팩토리 패턴은
팩토리를 사용하는 방법(composition)에 초점을 둔다.- 관련 있는 객체들을 어떻게 생성할 것인가?
- 팩토리 메서드 패턴은
- 둘은 목적이 다르다.
- 팩토리 메서드 패턴은 구체적인 객체 생성 과정을 하위 또는 상위 클래스로 옮기는 것이 목적
ConcreteClass를 구현하는 것에 목적을 둠- 상속의 관점
- 추상 팩토리 패턴은 관련있는 여러 객체를 구체적인 클래스에 의존하지 않고 만들 수 있게 하는 것이 목적
ConcreteClass구현 자체보다는 클라이언트에서 추상화된 팩토리를 사용하는 것에 더 초점을 맞춤- 구성의 관점
- 팩토리 메서드 패턴은 구체적인 객체 생성 과정을 하위 또는 상위 클래스로 옮기는 것이 목적
추상 팩토리 패턴의 용례
추상 팩토리 패턴의 용례에 대해 알아보자.
DocumentBuilderFactory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src/main/resources/config.xml"));
System.out.println(document.getDocumentElement());DocumentBuilderFactory추상 클래스는 추상 메서드인newDocumentBuilder()를 통해DocumentBuilder를 제공하는 것에 관심이 있다.- 팩토리 메서드 패턴과 비교하자면, 어떻게 제공 메서드를 구현할 것이냐보다도 그냥 어떤 종류의
DocumentBuilder를 제공할 것이냐에 관심이 있다. - 이와 비슷한 종류로
XPathFactory,TransformerFactory가 있다.
FactoryBean
FactoryBean은 스프링의 인터페이스로 보통new키워드로 간단히 생성하기 힘든 객체가 있을 때 이를 이용한다.
public class CarFactoryBean implements FactoryBean<Car> {
private final CarFactory carFactory = new CarFactory(new K9PartsFactory());
@Override
public Car getObject() throws Exception {
return carFactory.createCar();
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
}
@Configuration
public class FactoryBeanConfig {
@Bean
public CarFactoryBean carFactory() {return new CarFactoryBean();}
}
public class FactoryBeanExample {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(FactoryBeanConfig.class);
Car bean = applicationContext.getBean(Car.class);
System.out.println(bean);
}
}CarFactoryBean의 구현을 보면,Bean으로 등록되기 위해 필요한 메서드들이 몰려있는 것을 볼 수 있다.getObject()와getObjectType()을 꼭 구현해야 한다.FactoryBean인터페이스는 어떤 메서드들의 구현을 조합해야Bean을 생성할 수 있는지에 관심이 있다.
- 실제로
FactoryBeanConfig에서 등록한Bean은CarFactoryBean인데 애플리케이션 컨텍스트에서 등록한적 없는Car타입의 빈을 잘 찾아낸다.- 스프링이
FactoryBean을 인식하고FactoryBean의 로직에 따라Bean을 잘 만들어주었기 때문이다.
- 스프링이
레퍼런스
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard
'Java > 자바 디자인 패턴' 카테고리의 다른 글
| 프로토타입 패턴 (Prototype Pattern) 이란? (2) | 2023.01.28 |
|---|---|
| 빌더 패턴 (Builder Pattern) 이란? (0) | 2023.01.26 |
| 팩토리 메서드 패턴 (Factory Method Pattern) 이란? (0) | 2023.01.23 |
| 싱글톤 패턴 (Singleton Pattern) 이란? (0) | 2023.01.20 |
| 자바 믹스인(mixins)이란? (0) | 2021.12.30 |