프로토타입 패턴은 싱글톤과 같이 생성 패턴(Creathinal Patterns) 중 하나이다.
기존 인스턴스를 프로토타입으로 사용하여 복제해 새로운 인스턴스를 생성하는 디자인 패턴이다.
최상위 객체인 Object 객체의 clone() 메서드를 활용하여 객체를 복제할 수 있다.
실제 clone() 메서드를 오버라이드 하고자 한다면, Cloneable 인터페이스를 구현하면 된다.
아래와 같은 클래스가 있다고 가정하자.
public class GithubIssue {
private int id;
private String title;
private GithubRepository repository;
public GithubIssue(GithubRepository repository) {
this.repository = repository;
}
//getter & setter
}
일반적으로 해당 클래스를 인스턴스로 생성하고자 한다면, 아래와 같이 될 것이다.
public class App {
public static void main(String[] args) {
GithubRepository repository = new GithubRepository();
GithubIssue githubIssue = new GithubIssue(repository);
githubIssue.setId(1);
githubIssue.setTitle("1주차 과제: JVM");
}
}
Clone을 사용하여 객체를 복제할 수 있다.
public class GithubIssue implements Cloneable {
private int id;
private String title;
private GithubRepository repository;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
이 경우, 원본 객체와 clone()으로 복제한 객체는 새로운 객체이지만,
내부 필드의 객체는 동일한 주소값을 가르키고 있는 문제가 있다.(얕은 복사 - Shallow copy)
public class App {
public static void main(String[] args) throws CloneNotSupportedException {
GithubRepository repository = new GithubRepository();
GithubIssue githubIssue = new GithubIssue(repository);
githubIssue.setId(1);
githubIssue.setTitle("1주차 과제: JVM");
GithubIssue clone = (GithubIssue) githubIssue.clone();
System.out.println(clone == githubIssue); // false
System.out.println(clone.getClass() == githubIssue.getClass()); // true
System.out.println(clone.getRepository() == githubIssue.getRepository()); // true
}
}
이 경우 오버라이딩 한 clone() 메서드를 재정의 하면 된다.
결국 깊은복사(Deep copy)가 되도록 모든 필드에 대해 재정의 해주어야 한다.
이러한 로직은, 구현부에서 정의하던 객체 생성 부분을 내부로 가져와 숨길 수 있다.
public class GithubIssue implements Cloneable {
//중략
@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;
}
}
System.out.println(clone.getRepository() == githubIssue.getRepository()); // false
디자인 패턴을 학습하기 위해 정리하였지만,
사실 effective java에서는 앞서 언급한 얕은 복사 문제로 인해, clone() 메서드의 사용에 대해 주의를 요한다.
참고 : 인프런, 백기선, 코딩으로 학습하는 GoF의 디자인 패턴(https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/)
'개발 > Java' 카테고리의 다른 글
[Java] Design-Pattern : Singleton(2) (0) | 2024.01.27 |
---|---|
[Java] Design-Pattern : Singleton(1) (0) | 2024.01.21 |
[Java] 예외의 종류(Checked, UnChecked, Error) (0) | 2023.07.30 |
[Java] Enum 에 대해 (0) | 2023.07.09 |
[Java] JVM - ClassLoader(아주 얕은 수준) (0) | 2022.09.03 |