본문 바로가기
Design Pattern

5. 프로토타입 패턴(Prototype Pattern)

by 킹차니 2021. 12. 16.

 

 

프로토타입 패턴 

: 기존 인스턴스를 복제하여 새로운 인스턴스를 만드는 방법. 기존의 객체를 응용하여 새로운 객체를 만들 때 사용한다. 특히 기존의 인스턴스를 만들 때 시간이 오래걸리는 작업. 가령 데이터 베이스에서 데이터를 읽어와서 인스턴스를 생성한다던가 http 요청을 보내서 가져온 데이터로 인스턴스를 만들어야 하는 경우는 상대적으로 오랜시간과 큰 리소스가 필요한 작업이다. 이 때 DB나 http통신으로 가져온 데이터를 복제를 해서 새로운 인스턴스를 만들고 원하는 값만 일부 변경하여 사용한다.

 


 

코드로 살펴보기

 

이제 코드로 살펴보자. GithubRepository와 GitHubIssue객체가 있다.

 

만약 하나의 repository에 대해서 issue를 만들기 위해서 client코드는 아래와 같다.

실행 결과

그런데 만약 같은 repositiry에 대해서 새로운 issue를 추가하고 싶다면 새로운 issue를 만들어야한다.

새로운 issue 객체를 new해서 변경되어야 하는 부분들을 set해야 하는 것이다.

 

하지만 우리는 clone을 사용해서 아래와 같이 하고 싶은 것이다.



하지만 현재는 clone()이 컴파일 에러가 발생한다.(clone은 Object 클랙스 안에 있다.)

clone() :

clone()은 Object안에서 protected로 되어 있어서 현재 컴파일 에러가 발생한다.

하여 우리가 clone을 사용하기 위해서는 명시적으로 사용할 수 있도록 해주어여 한다.

 

이를 위해서는 아래와 같이 Cloneable 인터페이스를 implements하고 clone()메소드를 override해준다.

equls()메소드 역시 정말 안에 있는 값이 같은지 테스트하기 위해 override해주었다.

 

이제 아래와 같은 main을 실행해보자.

실행 결과

프로토 타입 객체(githubIssue)와 클론 객체(clone)는 래퍼런스는 다르지만, 내용물은 같은 것을 알 수 있다.

 

현재 우리가 사용하는(자바가 기본적으로 제공하는) clone()은 얕은 복사로 작동한다.

하여 githubIssue가 가지고 있는 githubRepository와 clone이 가지고 있는 githubRepository는 현재 같은 참조를 가진다.

 

그래서 clone과 githubIssue가 서로 영향을 미치지 않게 하기 위해,  프로토타입의 래퍼런스(githubRepository)를 가르키지 않고, 다른 래퍼런스를 참조하고 싶다면 githubIssue의 clone()메소드를 그대로 사용하는 것이 아닌 임의로 구현을 해주어야 한다.

 

수정된 clone()은 아래와 같다.

 


 

장점과 단점

 

장점 :

1. 복잡한 객체를 만드는 과정을 숨길 수 있다.

2. 기존 객체를 복제하는 과정이 새 인스턴스를 만드는 것보다 비용(시간 또는 메모리)적인 면에서 효율적일 수 있다.

3. 추상적인 타입을 리턴할 수 있다.

 

단점:

복잡한 객체를 만드는 과정 자체가 복잡할 수 있다. (특히 순환 참조가 있는 경우)

 

 


실제로 어디에서 사용되나?

 

1. 콜렉션의 복사

 

만약 애와 같은 Student컬렉션을 복사해야한다고 해보자.

 

우리가 배운 clone을 사용할 수 있을 것이다.

하지만 위 이미지의 빨간 박스에서 보이듯이 컬렉션은 직접적인 구현체보다 추상적인 List를 사용하는 것이 유연성에 있어서 좋기 때문에 ArrayList보단 List타입으로 한다. 하지만 List는 Cloneable을 implements하지 않는다.clone()을 사용하고 싶은 것과 유연성을 위해 List를 사용하고 싶은 것이 충돌되는 것이다.

 

하여 콜렉션의 복사는 아래와 같이 한다.

(그러나 실제로 위의 복사는 프로토타입 패턴은 아니다.)

 

 

 

 

2.Model Mapper

 

Model Mapper는 객체의 값들을 다른 객체로 복사해주는 편리한 라이브러리이다.

GithubIssueData는 GithubRepository와 GithubIssue 의 모든 데이터들을 flat하게 가지고 있는 객체이다.

 

ModelMapper를 사용하면 아래와 같이 쉽게 복사할 수 있다.

실행결과:

 

 

출처: 인프런 백기선님 '코딩으로 학습하는 GoF 강의'
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4