728x90
프로토타입(Prototype)패턴이란?
- 기존 인스턴스를 복제하여 새로운 인스턴스를 만드는 방법
- 복제 기능을 갖추고 있는 기존 인스턴스를 프로토타입으로 사용해 새 인스턴스를 만들 수 있다.
프로토타입 사용방법
- 프로토타입패턴 적용전
public class GithubRepository {
private String user;
private String name;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class GithubIssue {
private int id;
private String title;
private GithubRepository repository;
public GithubIssue(GithubRepository repository) {
this.repository = repository;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public GithubRepository getRepository() {
return repository;
}
public String getUrl() {
return String.format("https://github.com/%s/%s/issues/%d",
repository.getUser(),
repository.getName(),
this.getId());
}
}
public class App {
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);
GithubIssue githubIssue2 = new GithubIssue(repository);
githubIssue2.setId(2);
githubIssue2.setTitle("2주차~~");
}
}
- 프로토타입(얕은 복사)
- 자바가 제공하는 clone 기능은 얕은 복사가 기본값
- 원본의 값이 바뀌면 복사도 같이 변경된다.
// Cloneable을 implement 해준다.
public class GithubIssue implements Cloneable{
private int id;
private String title;
private GithubRepository repository;
public GithubIssue(GithubRepository repository) {
this.repository = repository;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public GithubRepository getRepository() {
return repository;
}
public String getUrl() {
return String.format("https://github.com/%s/%s/issues/%d",
repository.getUser(),
repository.getName(),
this.getId());
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GithubIssue that = (GithubIssue) o;
return id == that.id && Objects.equals(title, that.title) && Objects.equals(repository, that.repository);
}
@Override
public int hashCode() {
return Objects.hash(id, title, repository);
}
}
public class App {
public static void main(String[] args) throws CloneNotSupportedException {
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);
GithubIssue clone = (GithubIssue) githubIssue.clone();
System.out.println(clone.getUrl());
//true
System.out.println(clone != githubIssue);
//true
System.out.println(clone.equals(githubIssue));
//true
System.out.println(clone.getClass() == githubIssue.getClass());
//true
System.out.println(clone.getRepository() == githubIssue.getRepository());
}
}
- 프로토타입(깊은 복사)
//일일히 값을 넣어주면 됨
@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;
}
장점
- 복잡한 객체를 만드는 과정을 숨길 수 있다.
- 기존 객체를 복제하는 과정이 새 인스턴스를 만드는 것보다 비용(시간 또는 메모리)적인면에서 효율적일 수도 있다.
- 추상적인 타입을 리턴할 수있다.
단점
- 복제한 객체를 만드는 과정 자체가 복잡할 수 있다.(특히, 순환 참조가 있는 경우)
실무에서 쓰이는 방법
public class JavaCollectionExample {
public static void main(String[] args) {
Student keesun = new Student("keesun");
Student whiteship = new Student("whiteship");
//실무에서는 아래 방법을 사용하지 않음
//ArrayList<Student> students = new ArrayList<>();
//실무에서 사용하는 방법
//1. 추상적인 타입을 사용함(List)
// - List에서는 clonable 상속하지 않음
// - 대신 ArrayList가 clonable을 상속하고 있음
List<Student> students = new ArrayList<>();
students.add(keesun);
students.add(whiteship);
//ArrayList<Student> clone = (ArrayList<Student>) students.clone();
//프로토타입을 사용방법은 아니지만, ArrayList를 사용해서 클론을 만들수 있다.
List<Student> clone = new ArrayList<>(students);
System.out.println(clone);
}
}
public class ModelMapperExample {
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은 무엇이며 자바 코드는 어떻게 실행하는 것인가.");
//일일이 데이터를 담는 방식
// GithubIssueData githubIssueData = new GithubIssueData();
// githubIssueData.setId(githubIssue.getId());
// githubIssueData.setRepositoryName(githubIssue.getRepository().getName());
//ModelMapper를 사용해서 담는 방식
//동작원리는 리플렉션을 이용해서 동작
ModelMapper modelMapper = new ModelMapper();
GithubIssueData githubIssueData = modelMapper.map(githubIssue, GithubIssueData.class);
System.out.println(githubIssueData);
}
}
728x90
'이론 > GoF' 카테고리의 다른 글
[구조패턴] 어댑터 패턴 (0) | 2023.07.24 |
---|---|
[구조패턴] 플라이웨이트 패턴 (0) | 2023.07.20 |
[생성패턴] 빌더패턴 (0) | 2023.05.23 |
[생성패턴] 추상팩토리 패턴 (0) | 2023.05.22 |
[생성패턴] 팩토리 메소드 패턴 (0) | 2023.05.22 |