개발자로 후회없는 삶 살기
디자인 패턴 PART.프로토타입 패턴 본문
서론
※ 이 포스트는 다음 강의의 학습이 목표임을 밝힙니다.
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard
본론
- 프로토타입 패턴 소개
기존 객체를 복제하여 새로운 객체를 만드는 방법으로 기존 객체를 응용할 때 유용하게 쓸 수 있습니다. DB 요청이나 네트워크 요청으로 가져온 데이터는 또 가져오려면 요청이 필요할 것입니다. 그때 이미 가져온 데이터를 복제를 해서 새로운 객체를 만들고 거기서 원하는 값만 바꿔서 쓴다면 훨씬 간단할 것입니다.
-> 그림
프로토타입 인터페이스의 clone 추상 메서드가 있고 복제 기능을 제공할 구현 클래스가 프로토타입을 구현하고 clone 안에서 기존 데이터를 원하는 형태로 복제하는 코드를 넣으면 됩니다. 클라는 clone 메서드만 사용하면 복제를 할 수 있습니다.
- 기존 코드
public class GithubRepository {
private String user;
private String name;
public class GithubIssue {
private int id;
private String title;
private GithubRepository repository;
GithubIssue, Github 레포라는 클래스가 있고 레포에는 user와 레포 이름이 있고 이슈에는 id와 title, 이슈가 속한 레포 정보가 있습니다.
public static void main(String[] args) {
GithubRepository repository = new GithubRepository();
repository.setUser("whiteship");
repository.setName("live-study");
GithubIssue githubIssue = new GithubIssue(repository);
githubIssue.setId(1);
githubIssue.setTitle("1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.");
String url = githubIssue.getUrl();
System.out.println(url);
}
App은 클라이언트 코드로 레포와 이슈 정보를 가지고 이슈에 해당하는 URL을 만드는 코드입니다. 근데 두번째 이슈를 만드려면 위 정보를 다 입력을 해서 만드는 것이 아니라 대부분의 데이터는 동일하고 이슈 정보만 바꾸면 되기 때문에 GithubIssue 객체를 기존의 이슈 객체를 복제해서 만들고 싶은 것입니다.
GithubIssue githubIssue2 = new GithubIssue(repository);
// 이것만 있으면 좋겠다.
githubIssue2.setId(2);
githubIssue2.setTitle("2주차 과제");
new GithubIssue하는 부분은 없어지고 set하는 2줄만 남기고 싶습니다.
GithubIssue githubIssue2 = githubIssue.clone()
githubIssue2.setId(2);
githubIssue2.setTitle("2주차 과제");
기존에 있던 인스턴스를 프로토타입으로 쓴다는 개념입니다.
-> 만든 후 따질 조건 ✅
1. == 은 어떻게 될까요?
클론한 객체와 원본은 다른 객체이여야 해서 false입니다.
2. equals()는?
내용물은 같아서 true가 나와야 합니다. 즉 레퍼런스는 새로운 객체라 다르지만 내용은 같은 객체를 만들게 될 것입니다.
- 패턴 적용하기
기존 패턴과는 다르게 자바가 제공하는 기능을 그대로 사용할 것입니다. 자바가 객체를 복제하는 매커니즘을 제공합니다.
-> githubIssue의 clone
clone이라는 메서드는 Object안에 있습니다. 근데 protected입니다. 따라서 githubIssue에서 clone을 지원하도록 구현을 해야합니다.
public class GithubIssue implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
클론하려는 객체에서 Clonable 인터를 구현하고 clone 메서드를 재정의하면 되고 super.clone()을 그대로 사용하면 자바가 기본으로 제공하는 클론 매커니즘을 이용할 수 있습니다. 오버라이딩 시에 가끔 기본 코드가 있는 경우가 있는데 이는 인텔리제이가 기본으로 구현해줘야 할 코드를 미리 구현을 해둔 것입니다.( ex clone )
-> 클라이언트 코드
GithubIssue githubIssue2 = (GithubIssue) githubIssue.clone();
System.out.println(githubIssue2.getUrl());
그러면 이제 githubIssue clone()을 할 수 있습니다. 타입이 Object라서 형변환을 하면 됩니다.
실행해보면 동일한 URL이 나옵니다.
-> clone 조건 체크
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GithubIssue that)) return false;
return getId() == that.getId() && Objects.equals(getTitle(), that.getTitle()) && Objects.equals(getRepository(), that.getRepository());
}
!=, equals가 true가 나옵니다. 당연히 equals는 재정의를 해줘야합니다. 이렇게 하면 위의 set하는 동일한 작업을 반복하지 않아도 되는 것입니다. 만약 GithubIssue가 DB를 다녀와야 한다던가 리소스 소모가 많은 작업이었다면 복제해서 사용했을 시 장점이 많습니다.
-> 주의점
자바의 clone은 shallow copy를 제공합니다. 얕은 복사로 기존 githubIssue를 변경하면 issue2도 변경이 됩니다.
이슈에 있던 레포지토리를 이슈2는 어떻게 가지고 있을까요? ✅
GithubRepository repository = new GithubRepository();
repository.setUser("whiteship");
repository.setName("live-study");
GithubIssue githubIssue = new GithubIssue(repository);
이슈는 new해서 레포를 가지고 있는데 이슈2도 new해서 가지고 있을까요? shallow copy는 이슈1과 2가 가지고 있는게 같은 것입니다.
이렇게 되면 레포가 변경되면 이슈 1과 2의 내용이 동일하게 변경됩니다.
완전 새로운 클론을 하고 싶다면? ✅
@Override
protected Object clone() throws CloneNotSupportedException {
GithubRepository repository = new GithubRepository();
repository.setUser(this.repository.getUser());
repository.setName(this.repository.getName());
GithubIssue githubIssue = new GithubIssue(repository);
githubIssue.setId(this.id);
githubIssue.setTitle(this.title);
return githubIssue;
}
deep copy를 하려면 재정의한 clone을 바꿔줘야 합니다. 자바가 기본으로 제공하는 클론 기능을 사용하지 않게 됩니다.
- 장점
자바를 사용하기 때문에 프로토타입을 쉽게 만들 수 있었습니다. 이렇게 하면 객체를 만들어서 set을 다시 전부 다 하는 과정을 clone이라는 메서드에 숨겨 놓을 수 있었고 리소스를 효율적으로 처리할 수 있었습니다.
'[백엔드] > [Java | 학습기록]' 카테고리의 다른 글
디자인 패턴 PART.브릿지 패턴 (0) | 2023.08.18 |
---|---|
디자인 패턴 PART.어댑터 패턴 (0) | 2023.08.18 |
디자인 패턴 PART.빌더 패턴 (0) | 2023.08.17 |
디자인 패턴 PART.추상 팩토리 패턴 (0) | 2023.08.13 |
디자인 패턴 PART.팩토리 메서드 패턴 (0) | 2023.08.13 |