Design Pattern

[디자인 패턴] 추상 팩토리 패턴 (Abstract Factory Pattern)

꾸준함. 2024. 6. 18. 20:44

추상 팩토리 패턴

  • 구체적인 클래스의 인스턴스를 생성하는 방법을 캡슐화하여 일관된 방식으로 연관된 객체를 생성할 수 있게 지원하는 패턴
    • Concrete Factory에서 Concrete Instance를 만들어주는 것까지는 팩토리 메서드 패턴과 비슷하지만
    • 초점이 팩토리를 사용하는 클라이언트 쪽에 있음
    • 목적 자체가 팩토리에서 인스턴스를 만드는 코드를 인터페이스 기반으로 구현할 수 있게끔 지원해 주는 패턴
    • 구체적인 클래스에 의존하지 않고 객체를 생성할 수 있기 때문에 클라이언트 코드를 변경하지 않아도 됨

 

https://www.codecademy.com/resources/docs/general/creational-design-patterns/abstract-factory-pattern

 

부연 설명

  • 팩토리 메서드 패턴에서 Client만 추가되었다고 생각해도 무방

 

추상 팩토리 패턴 구현 예시

  • 앞서 설명했다시피 추상 팩토리 메서드 패턴과 유사하지만 초점이 클라이언트에서 팩토리를 사용하는 방법에 있음

 

1. Factory 인터페이스 및 ConcreteFactory 정의

 

interface AbstractFactory {
AbstractProduct getProduct();
}
public class ConcreteFactoryA implements AbstractFactory {
@Override
public AbstractProduct getProduct() {
return new ProductA();
}
}
class ConcreteFactoryB implements AbstractFactory {
@Override
public AbstractProduct getProduct() {
return new ProductB();
}
}
view raw .java hosted with ❤ by GitHub

 

2. Product 인터페이스 및 다양한 Product 정의

 

public interface AbstractProduct {
void productFunc();
}
public class ProductA implements AbstractProduct {
@Override
public void productFunc() {
System.out.println("ProductA");
}
}
public class ProductB implements AbstractProduct {
@Override
public void productFunc() {
System.out.println("ProductB");
}
}
view raw .java hosted with ❤ by GitHub

 

3. 추상 팩토리 패턴을 사용하는 클라이언트 코드 작성

 

public class Client {
private AbstractProduct product;
public Client(AbstractFactory factory) {
this.product = factory.getProduct();
}
public static void main(String[] args) {
createClientAndRunProductFunc(new ConcreteFactoryA());
createClientAndRunProductFunc(new ConcreteFactoryB());
}
private static void createClientAndRunProductFunc(AbstractFactory factory) {
Client client = new Client(factory);
client.product.productFunc();
}
}
view raw .java hosted with ❤ by GitHub

 

부연 설명

  • 추상 팩토리 메서드 패턴과 달리 클라이언트 코드가 바뀌지 않음

 

팩토리 메서드 패턴 vs 추상 팩토리 패턴

 

  팩토리 메서드 패턴 추상 팩토리 패턴
공통점 두 패턴 모두 구체적인 객체 생성 과정을 추상화한 인터페이스를 제공
관점 팩토리를 구현하는 방법(inheritance)에 초점을 둠 팩토리를 사용하는 방법(composition)에 초점을 둠
목적 구체적인 객체 생성 과정을 하위 또는 구체적인 팩토리로 옮기는 것이 목적 관련있는 여러 객체를 구체적인 클래스에 의존하지 않고 생성할 수 있게 해주는 것이 목적

 

실무에서 쓰이는 추상 팩토리 패턴

 

1. 단순한 추상 팩토리 패턴

  • xml 형태의 문서를 자바 클래스로 변환해주는 DocumentBuilderFactory
  • 추상적인 타입인 DocumentBuilder 기반으로 구현하게 됨으로 추상 팩토리 패턴이라 할 수 있음

 

public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); // 추상적인 타입인 DocumentBuilder 기반으로 구현하게 됨으로 추상 팩토리 패턴이라 할 수 있음
Document document = builder.parse(new File("src/main/resources/config.xml"));
System.out.println(document.getDocumentElement());
}
view raw .java hosted with ❤ by GitHub

 

2. 스프링에서 제공하는 FactoryBean 인터페이스

  • Bean Object를 만들 때 만드는 과정이 단순히 생성자를 통해 만들 수 없고 좀 복잡할 경우 FactoryBean의 구현체를 만들어서 빈으로 등록
    • FactoryBean에서 만들어주는 Object가 빈으로 등록 (getObject 참고)

 

2.1 config.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="java.lang.String">
<constructor-arg value="hello"/>
</bean>
<bean id="hexagonal" class="com.tistory.jaimemin.designpattern.abstract_factory.java.TemplateFactory"/>
</beans>
view raw .xml hosted with ❤ by GitHub

 

2.2 FactoryBean 구현체 및 FactoryBean 사용하는 클라이언트 코드

 

@Component
public class TemplateFactory implements FactoryBean<Template> {
@Override
public Template getObject() throws Exception {
Template template = new HexagonalTemplate();
template.setName("hexagonal");
return template;
}
@Override
public Class<?> getObjectType() {
return Template.class;
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("config.xml");
Template hexagonalTemplate = applicationContext.getBean("hexagonal", Template.class);
System.out.println(hexgonalTemplate.getName());
}
view raw .java hosted with ❤ by GitHub

 

부연 설명

  • 프레임워크를 만드는 쪽에 보통 추상 팩토리 메서드 패턴 혹은 추상 팩토리 패턴이 많이 적용되어 있음
  • 스프링 프레임워크 내부 코드는 바뀌지 않으면서 확장 가능하기 때문에 OCP 원칙을 따랐다고 할 수 있음

 

참고

코딩으로 학습하는 GoF의 디자인 패턴 - 백기선 강사님

 

반응형