본문 바로가기

Develop/Design Pattern

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

728x90

해당 포스팅은 [Design Pattern] 팩토리 (Factory) 패턴 의 하위 문서입니다.



1. 개요

추상 팩토리 디자인 패턴 (Abstract Factory Design Pattern) (이하 추상 팩토리) 은 관련된 여러 객체들의 생성(Creation)과 책임(Responsibility)을 공장(Factory) 의 하위 클래스에 위임(Delegate) 하여 하위 클래스에서 연관된 객체들을 생성하고 이들을 조합하여 사용할 수 있도록 하는 패턴이다.

추상 팩토리 여러 메소드로 이루어진 인터페이스를 제공하고 각 메소드는 서로 연관된 객체를 생성한다.

2. 상황

  • 객체 생성이 복잡하거나 변경되기 쉬울 때
  • 객체 생성 코드가 중복될 때

3. 다이어그램

3.1. 설명

  • Product1, Product2: 제품군에 해당하는 추상 클래스이다.
  • Product1A, Product1B, Product2A, Product2B: Product1, Product2 각각에 대응되는 하위 구체 클래스이다.
  • Factory: 추상 클래스이다.
  • FactoryA, FactoryB: Factory 클래스의 하위 구현 클래스로 제품을 생성하는 역할을 수행한다.
  • createProduct1(), createProduct2(): 각 Factory 구체 클래스에서 구현된 메소드로, 각각의 제품군에 해당하는 Product1Product2 객체를 생성한다.

4. 구현

abstract class Product1 {}

class Product1A extends Product1 {}
class Product1B extends Product1 {}

abstract class Product2 {}

class Product2A extends Product2 {}
class Product2B extends Product2 {}
public abstract class Factory {
  public abstract Product1 createProduct1();
  public abstract Product2 createProduct2();
}

class FactoryA extends Factory {
  @Override
  public Product1A createProduct1() { return new Product1A(); }
  @Override
  public Product2A createProduct2() { return new Product2A(); }
}

class FactoryB extends Factory {
  @Override
  public Product1B createProduct1() { return new Product1B(); }
  @Override
  public Product2B createProduct2() { return new Product2B(); }
}
public class Client {
  public static void main(String[] args) {
    Factory factoryA = new FactoryA();
    Factory factoryB = new FactoryB();

    Product1A product1A = factoryA.createProduct1();
    Product2A product2A = factoryA.createProduct2();
    Product1B product1B = factoryB.createProduct1();
    Product2B product1B = factoryB.createProduct2();
  }
}

5. 예시

import java.util.ArrayList;
import java.util.List;

public abstract class Calculator<T> {
  public abstract T execute(T a, T b);
}

abstract class Adder<T> extends Calculator<T> {}
abstract class Subtractor<T> extends Calculator<T> {}

class NumberAdder extends Adder<Double> {
  @Override
  public Double execute(Double a, Double b) { return a + b; }
}

class StringAdder extends Adder<String> {
  @Override
  public String execute(String a, String b) { return a + b; }
}

class ListAdder<T> extends Adder<List<T>> {
  @Override
  public List<T> execute(List<T> a, List<T> b) {
    List<T> list = new ArrayList<>(a);
    list.addAll(b);
    return list;
  }
}


class NumberSubtractor extends Subtractor<Double> {
  @Override
  public Double execute(Double a, Double b) { return a - b; }
}

class StringSubtractor extends Subtractor<String> {
  @Override
  public String execute(String a, String b) { 
    String text = a;
    return text.replace(b, "");
  }
}

class ListSubtractor<T> extends Subtractor<List<T>> {
  @Override
  public List<T> execute(List<T> a, List<T> b) {
    List<T> list = new ArrayList<T>(a);
    list.removeAll(b);
    return list;
  }
}
import java.util.List;

public abstract class CalculatorFactory<T> {
  public abstract Calculator<T> createAdder();
  public abstract Calculator<T> createSubtractor();
}

class NumberFactory extends CalculatorFactory<Double> {
  public Adder<Double> createAdder() {
    return new NumberAdder();
  }
  public Subtractor<Double> createSubtractor() {
    return new NumberSubtractor();
  }
}

class StringFactory extends CalculatorFactory<String> {
  public Adder<String> createAdder() {
    return new StringAdder();
  }
  public Subtractor<String> createSubtractor() {
    return new StringSubtractor();
  }
}

class ListFactory<T> extends CalculatorFactory<List<T>> {
  public Adder<List<T>> createAdder() {
    return new ListAdder<T>();
  }
  public Subtractor<List<T>> createSubtractor() {
    return new ListSubtractor<T>();
  }
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Client {
  public static void main(String[] args) {
    CalculatorFactory<Double> intFactory = new NumberFactory();
    Calculator<Double> numberAdder = intFactory.createAdder();
    Calculator<Double> numberSubtractor = intFactory.createSubtractor();

    Double numberLeft = 40.0;
    Double numberRight = 30.5;

    Double numberAddResult = numberAdder.execute(numberLeft, numberRight);
    Double numberSubtractResult = numberSubtractor.execute(numberLeft, numberRight);

    System.out.println("\n[Number]");
    System.out.println(numberLeft + " + " + numberRight + " = " + numberAddResult);
    System.out.println(numberLeft + " - " + numberRight + " = " + numberSubtractResult);

    CalculatorFactory<String> strFactory = new StringFactory();
    Calculator<String> strAdder = strFactory.createAdder();
    Calculator<String> strSubtractor = strFactory.createSubtractor();

    String strLeft = "abcd";
    String strRight = "bc";

    String strAddResult = strAdder.execute(strLeft, strRight);
    String strSubtractResult = strSubtractor.execute(strLeft, strRight);

    System.out.println("\n[String]");
    System.out.println(strLeft + " + " + strRight + " = " + strAddResult);
    System.out.println(strLeft + " - " + strRight + " = " + strSubtractResult);

    CalculatorFactory<List<Integer>> listFactory = new ListFactory<>();
    Calculator<List<Integer>> listAdder = listFactory.createAdder();
    Calculator<List<Integer>> listSubtractor = listFactory.createSubtractor();

    List<Integer> listLeft = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
    List<Integer> listRight = new ArrayList<>(Arrays.asList(2, 3));

    List<Integer> listAddResult = listAdder.execute(listLeft, listRight);
    List<Integer> listSubtractResult = listSubtractor.execute(listLeft, listRight);

    System.out.println("\n[List]");
    System.out.println(listLeft + " + " + listRight + " = " + listAddResult);
    System.out.println(listLeft + " - " + listRight + " = " + listSubtractResult);
  }
}

실행결과


[Number]
40.0 + 30.5 = 70.5
40.0 - 30.5 = 9.5

[String]
abcd + bc = abcdbc
abcd - bc = ad

[List]
[1, 2, 3, 4] + [2, 3] = [1, 2, 3, 4, 2, 3]
[1, 2, 3, 4] - [2, 3] = [1, 4]

6. 장단점

6.1. 장점

  • 코드 중복 최소화
  • 유연성, 확장성 증가
  • Client 코드 간소화

6.2. 단점

  • 새로운 객체를 추가 시 하위 클래스 생성 필요
  • 코드 복잡성 증가

관련 포스팅

참고자료

728x90