의도 : 객체 생성을 위한 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 생성할지에 대한 결정은 서브클래스가 내리도록 한다.
활용
구조
Product : 팩토리 매서드가 생성하는 객체의 인터페이스 정의
ConcreteProduct : 팩토리 매서드가 생성하는 객체
Creator : Product 타입 객체 반환하는 팩터리 메서드 인터페이스 선언
ConcreteCreator : 팩토리 메서드 재정의하여 ConcreteProduct 인스턴스 생성 후 반환
결과
구현
구현 방법은 크게 두가지이다.
매개변수를 통해 팩토리 매서드가 여러 종류의 제품을 생성하게 할 수도 있다.
지연 초기화(Lazy Initialization), 제네릭(Generic)을 사용하여 구현할 수도 있다.
추상 팩토리 패턴의 예제였던 핸드폰 생성 예제를 팩토리 매서드에 맞게 변형시켰다. PhoneFactory 클래스는 팩토리 메서드인 makeDisplay와 makeInnerDevice를 가지고 있다. makeDisplay는 매개변수를 받고 매개변수에 따라 필요한 디스플레이(LG, 삼성, 애플)를 생성하여 반환해준다. 반면 makeInnerDevice는 클래스별로 미리 지정된 InnerDevice를 생성하여 반환한다.
UML
팩토리 메소드로 생성되는 객체
Display.java
public abstract class Display {
public Display() {
}
public abstract void testDisplay();
}
class LgDisplay extends Display {
public LgDisplay() {}
@Override
public void testDisplay() {
System.out.println("LG 디스플레이 테스트");
}
}
class SamsungDisplay extends Display {
public SamsungDisplay() {}
@Override
public void testDisplay() {
System.out.println("삼성 디스플레이 테스트");
}
}
class AppleDisplay extends Display {
public AppleDisplay() {}
@Override
public void testDisplay() {
System.out.println("애플 디스플레이 테스트");
}
}
InnerDevice.java
public class InnerDevice {
public InnerDevice() {
}
public void testKeyboardInput() {
System.out.println("기본 키보드 입력 테스트");
}
public void testMicrophoneInput() {
System.out.println("기본 마이크 입력 테스트");
}
}
class SamsungInnerDevice extends InnerDevice {
public SamsungInnerDevice() {
}
@Override
public void testKeyboardInput() {
System.out.println("삼성 키보드 입력 테스트");
}
@Override
public void testMicrophoneInput() {
System.out.println("삼성 마이크 입력 테스트");
}
}
class AppleInnerDevice extends InnerDevice {
public AppleInnerDevice() {
}
@Override
public void testKeyboardInput() {
System.out.println("애플 키보드 입력 테스트");
}
@Override
public void testMicrophoneInput() {
System.out.println("애플 마이크 입력 테스트");
}
}
Phone.java
public class Phone {
private Display display;
private InnerDevice innerDevice;
public void setDisplay(Display display) {
this.display = display;
}
public Display getDisplay() {
return display;
}
public void setInnerDevice(InnerDevice innerDevice) {
this.innerDevice = innerDevice;
}
public InnerDevice getInnerDevice() {
return innerDevice;
}
}
팩토리 메서드를 가지는 객체
PhoneFactory.java
public class PhoneFactory {
PhoneFactory() {}
//An Operation
public Phone createPhone(int item) {
Phone phone = new Phone();
phone.setInnerDevice(makeInnerDevice());
phone.setDisplay(makeDisplay(item));
return phone;
}
//Factory Method
public Display makeDisplay(int item) {
if (item == 0) return new LgDisplay();
else return null;
}
public InnerDevice makeInnerDevice() {
return new InnerDevice();
}
}
class SamsungPhoneFactory {
SamsungPhoneFactory() {}
//An Operation
public Phone createPhone(int item) {
Phone phone = new Phone();
phone.setInnerDevice(makeInnerDevice());
phone.setDisplay(makeDisplay(item));
return phone;
}
//Factory Method
public Display makeDisplay(int item) {
if (item == 0) return new LgDisplay();
if (item == 1) return new SamsungDisplay();
if (item == 2) return new AppleDisplay();
else return null;
}
public InnerDevice makeInnerDevice() {
return new SamsungInnerDevice();
}
}
class ApplePhoneFactory {
ApplePhoneFactory() {}
//An Operation
public Phone createPhone(int item) {
Phone phone = new Phone();
phone.setInnerDevice(makeInnerDevice());
phone.setDisplay(makeDisplay(item));
return phone;
}
//Factory Method
public Display makeDisplay(int item) {
if (item == 0) return new LgDisplay();
if (item == 1) return new SamsungDisplay();
if (item == 2) return new AppleDisplay();
else return null;
}
public InnerDevice makeInnerDevice() {
return new AppleInnerDevice();
}
}
메인 함수
TestFactoryMethodPattern.java
public class TestFactoryMethodPattern {
public static void main(String[] args) {
PhoneFactory basicPhoneFactory = new PhoneFactory();
SamsungPhoneFactory samsungPhoneFactory = new SamsungPhoneFactory();
ApplePhoneFactory applePhoneFactory = new ApplePhoneFactory();
Phone phone;
System.out.println("기본 핸드폰 생성");
System.out.println("LG 디스플레이 사용");
phone = basicPhoneFactory.createPhone(0);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n삼성 디스플레이 사용");
phone = basicPhoneFactory.createPhone(1);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n애플 디스플레이 사용");
phone = basicPhoneFactory.createPhone(2);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n삼성 핸드폰 생성");
System.out.println("LG 디스플레이 사용");
phone = samsungPhoneFactory.createPhone(0);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n삼성 디스플레이 사용");
phone = samsungPhoneFactory.createPhone(1);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n애플 디스플레이 사용");
phone = samsungPhoneFactory.createPhone(2);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n애플 핸드폰 생성");
phone = applePhoneFactory.createPhone(0);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n삼성 디스플레이 사용");
phone = applePhoneFactory.createPhone(1);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
System.out.println("\n애플 디스플레이 사용");
phone = applePhoneFactory.createPhone(2);
phone.getDisplay().testDisplay();
phone.getInnerDevice().testKeyboardInput();
phone.getInnerDevice().testMicrophoneInput();
}
}
GoF의 디자인 패턴을 읽고도 추상 팩토리 패턴과 팩토리 메서드 패턴의 차이점을 정확히 알기 어려워 다른 자료를 찾아보며 고민해봤다.
내가 이해한 차이점은 추상 팩토리 패턴은 한 클래스가 특정한 조건을 만족하는 한 종류의 객체만을 생성하여 반환하도록 강제한다. 따라서 객체군을 생성하는데 유용한 패턴이다. 이전 추상클래스 포스트 예제에서 SamsungPhoneFactory는 삼성 Display와 InnerDevice만을 생성하였으며 ApplePhoneFactory는 애플 디스플레이와 InnerDevice만을 생성하였다.
하지만 팩토리 메서드 패턴은 이와 달리 한 클래스가 조건을 만족하는 여러 종류의 객체들을 생성할 수 있다. 위 예제를 예를 들면 PhoneFactory 객체는 InnerDevice만 자신 메이커의 부품을 사용하고 Display는 매개변수를 받아 그에 맞는 Display(LG, 삼성, 애플)를 생성하여 반환한다. 그로 인해 한 클래스가 여러 종류의 객체를 생성 및 반환한다는 차이가 있다.
팩토리 메서드는 어떤 인스턴스를 생성할 지 서브 클래스에서 지정하다는 점이 중요하다.
에릭 감마, 리처드 헬름, 랄프 존슨, 존 블리시디스, 『GoF의 디자인 패턴』, 프로텍 미디어, 2015
[디자인패턴] 의존성 주입이란? (0) | 2023.03.12 |
---|---|
[디자인패턴/Java] 원형 패턴( Prototype Pattern) (0) | 2022.04.11 |
[디자인패턴] 빌더 패턴 (Builder Pattern) (0) | 2022.03.25 |
[디자인패턴] 추상 팩토리 패턴 (Abstract Factory Pattern) (0) | 2022.03.23 |