프로토타입 패턴
- 기존 인스턴스를 복제하여 새로운 인스턴스를 만드는 방법
- 기존 객체를 응용해서 새로운 인스턴스를 만들 때 유용
- 특히 기존 인스턴스를 만들 때 DB 조회 혹은 API 호출 같이 비교적 시간이 오래 걸리는 작업이 선행되어야 하는 경우 유용
- 매번 DB 조회 혹은 API 호출을 하면 시간이 오래 걸리기 때문에 이미 해당 작업을 수행해서 완성된 인스턴스를 복제한 후 일부 필드를 변경하는 방식으로 새로운 인스턴스를 만드는 방식
- 객체 생성 비용을 줄이고, 객체 초기화 과정에서 발생하는 복잡성을 간단하게 처리 가능

주요 구성 요소
1. Prototype 인터페이스
- 객체가 자신을 복제할 수 있도록 하는 인터페이스를 정의
- 해당 인터페이스는 보통 clone() 메서드를 포함하며 자바에서 clone() 메서드는 protected native 메서드이기 때문에 Cloneable 인터페이스 구현체를 만들어 clone() 메서드를 재정의해야 함
* clone() 메서드 관련해서는 이펙티브 자바 아이템 13에서 다루었으므로 해당 게시글 참고하는 것을 권장드립니다.
2. Concrete Prototype
- 프로토타입 인터페이스를 구현한 실제 객체
- 해당 객체는 자시니의 복사본을 반환할 수 있어야 함
3. Client
- 새로운 객체를 생성할 때 직접 객체를 생성하는 대신 프로토타입 객체의 clone() 메서드를 호출하여 객체를 생성
프로토타입 구현 예시
1. Prototype 인터페이스 정의
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Prototype extends Cloneable { | |
} |
2. ConcretePrototype 정의
- ConcretePrototype을 생성하는데 5초가 걸린다고 가정
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Setter | |
@ToString | |
public class ConcretePrototype implements Prototype { | |
private String field; | |
public ConcretePrototype(String field) throws InterruptedException { | |
Thread.sleep(5000); // 생성 비용이 비싸 5초 걸린다고 가정 | |
this.field = field; | |
} | |
@Override | |
protected Object clone() throws CloneNotSupportedException { | |
return super.clone(); | |
} | |
} |
3. Client 코드 예시
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Client { | |
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException { | |
long start = System.nanoTime(); | |
ConcretePrototype prototype = new ConcretePrototype("original"); | |
long end = System.nanoTime(); | |
long duration = end - start; | |
System.out.println(String.format("prototype: %s, 생성 시간: %s나노초", prototype, duration)); | |
start = System.nanoTime(); | |
ConcretePrototype cloned = (ConcretePrototype) prototype.clone(); | |
cloned.setField("cloned"); | |
end = System.nanoTime(); | |
duration = end - start; | |
System.out.println(String.format("cloned: %s, 생성 시간: %s나노초", cloned, duration)); | |
} | |
} |

부연 설명
- 처음 생성한 인스턴스는 5초가 넘게 걸리지만
- 프로토타입 패턴을 적용한 cloned는 clone() 메서드를 호출하여 기존 인스턴스를 복제했으므로 1초도 안 걸리는 것을 확인 가능
프로토타입 패턴 장단점
장점
- 기존 인스턴스를 복제하는 방식이므로 복잡한 객체를 생성하는 과정을 은닉할 수 있음
- 기존 객체를 복제하는 고자어이 새 인스턴스를 생성하는 것보다 비용적인 면에서 효율적
- 추상적인 타입을 반환할 수 있음
단점
- 복제한 객체를 만드는 과정 자체가 복잡할 수 있음
- clone()은 기본적으로 얕은 복사를 지원하기 때문에 컴포지션을 이용한 객체의 경우 clone() 메서드를 재정의할 때 깊은 복사를 직접 구현해야 함
- 특히 객체 간 순환참조가 있는 경우 clone() 메서드 재정의하기가 상당히 까다로워질 수 있음
실무에서 쓰이는 프로토타입 패턴
1. ArrayList 생성자
- ArrayList는 Cloneable을 상속하기 때문에 clone() 메서드를 지원함
- 하지만 코드 상에서는 확장성을 위해 추상화된 인터페이스인 List 변수에 ArrayList를 저장
- List는 Cloneable을 상속하지 않았기 때문에 clone()을 지원 X
- ArrayList 생성자에 파라미터로 컬렉션을 넘겨주면 프로토타입 패턴 효과를 얻을 수 있음
- 엄밀히 말하면 프로토타입 패턴은 아니지만 비슷한 효과
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void main(String[] args) { | |
Student jaimemin = new Student("jaimemin"); | |
Student gudetama = new Student("gudetama"); | |
// ArrayList<Student> students = new ArrayList<>(); | |
// ArrayList<Student> clonedStudents = (ArrayList<Student>)students.clone(); | |
List<Student> students = new ArrayList<>(); | |
students.add(jaimemin); | |
students.add(gudetama); | |
List<Student> clone = new ArrayList<>(students); | |
System.out.println(clone); | |
} |
2. ModelMapper
- 자바 객체 간의 매핑을 간편하게 해주는 라이브러리이며 내부적으로 리플렉션을 이용
- 주로 DTO(Data Transfer Object)와 엔티티(Entity) 간의 변환 작업에서 사용
- 코드의 중복을 줄이고, 객체 변환의 복잡성을 줄일 수 있음
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Data | |
public class UserEntity { | |
private Long id; | |
private String username; | |
private String email; | |
} | |
@Data | |
public class UserDto { | |
private String username; | |
private String email; | |
} | |
public class ModelMapperExample { | |
public static void main(String[] args) { | |
ModelMapper modelMapper = new ModelMapper(); | |
UserEntity userEntity = new UserEntity(); | |
userEntity.setId(1L); | |
userEntity.setUsername("jaimemin"); | |
userEntity.setEmail("example@example.com"); | |
UserDto userDTO = modelMapper.map(userEntity, UserDto.class); | |
System.out.println(userDTO); | |
} | |
} |

참고
코딩으로 학습하는 GoF의 디자인 패턴 - 백기선 강사님
반응형
'Design Pattern' 카테고리의 다른 글
[디자인 패턴] 브릿지 패턴 (Bridge Pattern) (0) | 2024.06.22 |
---|---|
[디자인 패턴] 어댑터 패턴 (Adapter Pattern) (0) | 2024.06.22 |
[디자인 패턴] 빌더 패턴 (Builder Pattern) (0) | 2024.06.21 |
[디자인 패턴] 추상 팩토리 패턴 (Abstract Factory Pattern) (0) | 2024.06.18 |
[디자인 패턴] 팩토리 메서드 패턴 (Factory Method Pattern) (0) | 2024.06.18 |