티스토리 뷰
728x90
반응형
팩토리 메서드 패턴이란?
- 객체를 생성하기 위한 인터페이스를 정의하고 어떤 클래스의 인스턴스를 생성할지에 대한 처리는 서브 클래스가 결정하는 디자인패턴입니다.
- new 키워드를 호출해 객체를 생성하는 역할을 서브 클래스에 위임하는 것입니다. 그렇기 때문에 팩토리 메서드 패턴은 객체를 만들어 내는 공장 패턴이라 할 수 있습니다.
- 클래스의 인스턴스를 만드는 일은 서브 클래스에게 맡깁니다.
클래스 다이어 그램
💡 다양한 구현체(Product)가 있고, 그중에서 특정한 구현체를 만들 수 팩토리(Creator)를 제공할 수 있습니다.
💡 Product
- 인스턴스 생성시 큰 틀을 결정하는 추상 클래스 및 인터페이스입니다. 구체적인 내용(구현부)은 ConcreteProduct에서 결정합니다.
💡 ConcreteProduct
- 인스턴스 생성시 구체적인 인스턴스 생성을 결정합니다.
💡 Creator
- Product 타입의 객체를 반환하는 팩토리 메서드를 선언하는 클래스입니다.
- 팩토리 메서드를 기본적으로 구현하며, ConcreteProduct 객체를 반환합니다.
- Product 객체의 생성을 위해 팩토리 메서드를 호출합니다.
💡 ConcreteCreator
- 구체적인 인스턴스를 만드는 클래스입니다.
팩토리 메서드 패턴을 사용하지 않은 예제
@Getter
@Setter
@ToString
public class Ship {
private String name;
private String color;
}
// Ship을 생성하는 Factory
public class ShipFactory {
public static Ship createShip(String name, String buyer) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("배 이름을 지어주세요.");
}
if (buyer == null || buyer.isBlank()) {
throw new IllegalArgumentException("구매자를 남겨주세요.");
}
prepareFor(name);
Ship ship = new Ship();
ship.setName(name);
if (name.equalsIgnoreCase("whiteShip")) {
ship.setColor("white");
} else if (name.equalsIgnoreCase("blackShip")) {
ship.setColor("black");
}
sendAlarmTo(buyer, ship);
return ship;
}
private static void prepareFor(String name) {
System.out.println(name + " 만들 준비 중");
}
private static void sendAlarmTo(String buyer, Ship ship) {
System.out.println(buyer + "님 " + ship.getName() + " 다 만들었습니다.");
}
}
public class Client {
public static void main(String[] args) {
Ship WhiteShip = ShipFactory.createShip("WhiteShip", "홍길동");
System.out.println(WhiteShip);
// WhiteShip 만들 준비 중
// 홍길동님 WhiteShip 다 만들었습니다.
// Ship(name=WhiteShip, color=white)
Ship BlackShip = ShipFactory.createShip("BlackShip", "이순신");
System.out.println(BlackShip);
// BlackShip 만들 준비 중
// 이순신님 BlackShip 다 만들었습니다.
// Ship(name=BlackShip, color=black)
}
}
팩토리 메서드 패턴을 사용한 예제 1)
// Creator의 역할을 하는 인터페이스
public interface ShipFactory {
Ship creatingShip();
default Ship orderShip(String name, String buyer) {
validate(name, buyer);
prepareFor(name);
Ship ship = creatingShip();
sendAlarmTo(buyer, ship);
return ship;
}
private void validate(String name, String buyer) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("배 이름을 지어주세요.");
}
if (buyer == null || buyer.isBlank()) {
throw new IllegalArgumentException("구매자를 남겨주세요.");
}
}
private void prepareFor(String name) {
System.out.println(name + " 만들 준비 중");
}
private void sendAlarmTo(String buyer, Ship ship) {
System.out.println(buyer + "님 " + ship.getName() + " 다 만들었습니다.");
}
}
// ConcreteCreator의 역할을 하는 인터페이스
public class WhiteShipFactory implements ShipFactory {
@Override
public Ship creatingShip() {
return new WhiteShip();
}
}
public class BlackShipFactory implements ShipFactory {
@Override
public Ship creatingShip() {
return new BlackShip();
}
}
// Product의 역할을 하는 클래스 및 인터페이스
@Getter
@Setter
@ToString
public class Ship {
private String name;
private String color;
}
// ConcreteProduct의 역할을 하는 클래스
public class WhiteShip extends Ship {
public WhiteShip() {
setName("WhiteShip");
setColor("White");
}
}
public class BlackShip extends Ship {
public BlackShip() {
setName("BlackShip");
setColor("Black");
}
}
public class Client {
public static void main(String[] args) {
Ship whiteShip = new WhiteShipFactory().orderShip("WhiteShip", "홍길동");
System.out.println(whiteShip);
// WhiteShip 만들 준비 중
// 홍길동님 WhiteShip 다 만들었습니다.
// Ship(name=WhiteShip, color=White)
Ship blackShip = new BlackShipFactory().orderShip("BlackShip", "이순신");
System.out.println(blackShip);
// BlackShip 만들 준비 중
// 이순신님 BlackShip 다 만들었습니다.
// Ship(name=BlackShip, color=Black)
}
}
팩토리 메서드 패턴을 사용한 예제 2)
💡해당 예제는 필자의 생각대로 만들어본 예제입니다.
// Creator의 역할을 하는 인터페이스
public interface ShipFactory {
Ship creatingShip(Type type, String name, String color, String buyer);
}
// ConcreteCreator의 역할을 하는 클래스
public class DefaultFactory implements ShipFactory {
@Override
public Ship creatingShip(Type type, String name, String color, String buyer) {
validate(name, buyer);
prepareFor(name);
Ship ship = null;
switch (type) {
case BLACK_SHIP:
ship = new BlackShip(name, color);
break;
case WHITE_SHIP:
ship = new WhiteShip(name, color);
break;
default:
throw new RuntimeException(type.toString() + " is not existed");
}
sendAlarmTo(buyer, ship);
return ship;
}
private void validate(String name, String buyer) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("배 이름을 지어주세요.");
}
if (buyer == null || buyer.isBlank()) {
throw new IllegalArgumentException("구매자를 남겨주세요.");
}
}
private void prepareFor(String name) {
System.out.println(name + " 만들 준비 중");
}
private void sendAlarmTo(String buyer, Ship ship) {
System.out.println(buyer + "님 " + ship.getName() + " 다 만들었습니다.");
}
}
// Product의 역할을 하는 클래스 및 인터페이스
@Getter
@Setter
@ToString
public abstract class Ship {
private String name;
private String color;
}
// ConcreteProduct의 역할을 하는 클래스
public class WhiteShip extends Ship {
public WhiteShip(String name, String color) {
this.setName(name);
this.setColor(color);
}
}
public class BlackShip extends Ship {
public BlackShip(String name, String color) {
this.setName(name);
this.setColor(color);
}
}
// 타입
public enum Type {
WHITE_SHIP,
BLACK_SHIP
}
public class Client {
public static void main(String[] args) {
Ship whiteShip = new DefaultFactory().creatingShip(Type.WHITE_SHIP, "멋쟁이배", "white", "홍길동");
System.out.println(whiteShip);
// 멋쟁이배 만들 준비 중
// 홍길동님 멋쟁이배 다 만들었습니다.
// Ship(name=멋쟁이배, color=white)
Ship blackShip = new DefaultFactory().creatingShip(Type.BLACK_SHIP, "빠른배", "black", "이순신");
System.out.println(blackShip);
// 빠른배 만들 준비 중
// 이순신님 빠른배 다 만들었습니다.
// Ship(name=빠른배, color=black)
}
}
팩토리 메서드 패턴의 장단점
장점
- 팩토리 메서드 패턴은 직접 사용하는 객체를 생성하지 않고 팩토리 메서드 클래스를 통하여 객체를 대신 생성시키고 그 객체를 받환 받아 사용하기 때문에 결합도를 낮출 수 있습니다.
단점
- 객체가 늘어날때마다 하위 클래스를 재정의 해줘야하므로 너무 많은 클래스를 만들게 됩니다.
728x90
반응형
'JAVA > Design_Pattern' 카테고리의 다른 글
[Design_Pattern] 추상 팩토리 패턴 (0) | 2022.07.28 |
---|---|
[Design_Pattern] 프록시 패턴 (0) | 2022.03.23 |
[Design_Pattern] 파사드 패턴 (1) | 2022.03.13 |
[Design_Pattern] 데코레이터 패턴 (0) | 2022.03.11 |
[Design_Pattern] 컴포지트 패턴 (0) | 2022.03.07 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- spring boot 엑셀 다운로드
- JDK Dynamic Proxy와 CGLIB의 차이
- 람다 표현식
- spring boot redisson destributed lock
- @ControllerAdvice
- microkernel architecture
- transactional outbox pattern spring boot
- pipeline architecture
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- spring boot excel download paging
- service based architecture
- spring boot redis 대기열 구현
- polling publisher spring boot
- 서비스 기반 아키텍처
- 레이어드 아키텍처란
- java ThreadLocal
- spring boot excel download oom
- java userThread와 DaemonThread
- spring boot redisson 분산락 구현
- redis sorted set으로 대기열 구현
- redis 대기열 구현
- 자바 백엔드 개발자 추천 도서
- spring boot redisson sorted set
- 공간 기반 아키텍처
- pipe and filter architecture
- redis sorted set
- spring boot poi excel download
- transactional outbox pattern
- space based architecture
- 트랜잭셔널 아웃박스 패턴 스프링부트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함