[Design Pattern] GoF 생성 패턴 - 추상 팩토리 패턴(Abstract Factory Pattern)



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

GoF 디자인 패턴 중 생성 패턴에 해당한다.
추상 팩토리 패턴은 클래스에서 실제 구현부를 정의하지 않고 팩토리에 인터페이스를 생성하도록 요청하여 인스턴스를 가져온다. 따라서 인터페이스를 구현한 팩토리를 통해 서로 관련성이 있는 객체의 집합을 생성할 수 있다.
대표적인 예로 자바의 GUI 라이브러리인 AWT/Swing의 록앤필 기능이 있다. 운영체제에 따라 다른 디자인의 컴포넌트를 제공한다.


사용법

  • 객체의 생성·표현 방식과 무관하게 시스템을 독립적으로 만들고자 할 때
  • 여러 제품군 중 하나를 선택해 시스템을 설정해야 하고 한번 구성한 제품을 다른 것으로 대체할 수 있을 때
  • 관련 제품 객체들이 함께 사용되도록 설계되었고, 이 제약이 외부에도 지켜지도록 하고 싶을 때
  • 제품에 대한 클래스 라이브러리를 제공하고, 인터페이스만을 노출시키고 싶을 때


구조

img

  • AbstractFactory인터페이스를 정의하고 이를 상속받은 ConcreteFactory클래스를 구현한다.
  • AbstractProduct인터페이스를 정의하고 이를 상속받은 Product클래스를 구현한다.
  • ConcreteFactory의 인스턴스가 런타임에 생성되고, AbstractFactory는 Product의 생성을 ConcreteFactory에 위임한다.
  • ConcreteFactory는 실제 Product를 생성한다.
  • Client는 인터페이스를 통해 각 객체에 접근할 수 있다.


장점

  • 클라이언트 코드와 클래스의 구현을 분리할 수 있음
  • 객체 간의 일관성을 증진시킴
  • 구현부를 쉽게 수정할 수 있음 : 구현된 Product는 응용프로그램에서 한 번만 노출되기 때문에(AbstractProduct를 구현하는 부분) ConcreteFactory를 변경하기 쉽다.


단점

  • 새로운 종류의 Product를 제공하기 어려움 : 새로운 종류의 Product를 추가하려면 Factory의 구현을 변경해야하며 이에 따라 Factory인터페이스를 상속받은 모든 서브클래스도 수정해야한다.


예제

클래스 다이어그램

img


패키지 구조

img


구현

Main에서 Factory인터페이스를 생성하고 생성부분을 서브클래스인 AppleFactory와 SamsungFactory로 위임한다. Factory의 추상메소드를 통해 객체를 생성하고 인터페이스인 Phone과 Laptop을 통해 Apple과 Samsung 각각의 서브클래스를 참조할 수 있다.

(1) Samsung Factory

Factory factory = getFactory("Samsung");

Phone phone = factory.createPhone();
Laptop laptop = factory.createLaptop();

System.out.println(phone.getName());
System.out.println(laptop.getName());
[실행 결과]
GalaxyS20
GalaxyBook

(2) Apple Factory

Factory factory = getFactory("Apple");

Phone phone = factory.createPhone();
Laptop laptop = factory.createLaptop();

System.out.println(phone.getName());
System.out.println(laptop.getName());
[실행 결과]
IPhone
MacBook


소스 코드

전체 소스 코드

package abst;

public interface Factory {
    Phone createPhone();
    Laptop createLaptop();
}
package abst;

public interface Laptop {
    String getName();
}
package abst;

public interface Phone {
    String getName();
}
package apple;

import abst.Factory;
import abst.Laptop;
import abst.Phone;

public class AppleFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new IPhone();
    }

    @Override
    public Laptop createLaptop() {
        return new MacBook();
    }
}
package apple;

import abst.Phone;

public class IPhone implements Phone {
    @Override
    public String getName() {
        return "IPhone";
    }
}
package apple;

import abst.Laptop;

public class MacBook implements Laptop {

    @Override
    public String getName() {
        return "MacBook";
    }
}
package samsung;

import abst.Laptop;

public class GalaxyBook implements Laptop {
    @Override
    public String getName() {
        return "GalaxyBook";
    }
}
package samsung;

import abst.Phone;

public class GalaxyS20 implements Phone {
    @Override
    public String getName() {
        return "GalaxyS";
    }
}
package samsung;

import abst.Factory;
import abst.Laptop;
import abst.Phone;

public class SamsungFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new GalaxyS20();
    }

    @Override
    public Laptop createLaptop() {
        return new GalaxyBook();
    }
}
import abst.Factory;
import abst.Laptop;
import abst.Phone;
import apple.AppleFactory;
import samsung.SamsungFactory;

public class Main {
    public static void main(String[] args) {
        //Factory factory = getFactory("Apple");
        Factory factory = getFactory("Samsung");

        Phone phone = factory.createPhone();
        Laptop laptop = factory.createLaptop();

        System.out.println(phone.getName());
        System.out.println(laptop.getName());
    }

    static Factory getFactory(String name) {
        if ("Apple".equals(name)) {
            return new AppleFactory();
        } else if ("Samsung".equals(name)) {
            return new SamsungFactory();
        } else
            return null;
    }
}



:bookmark: REFERENCE
에릭 감마 외 3명, 「GoF의 디자인 패턴」, 피어슨에듀케이션코리아