프로토타입(prototype) 패턴

기존에 존재하는 객체를 복사해 생성하는 디자인 패턴이다
똑같은 상태를 가진 객체를 생성하는데 유리하다

예시

GithubRepository에 똑같은 이슈를 두개 생성하려고 한다.

프로토타입 패턴 구현 예제

Prototype에 Clonable을 구현하고, clone 함수를 오버라이드한다.

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);
    }

}

Concreate Builder

public class DefaultTourPlanBuilder implements TourPlanBuilder {

    private final List<DetailPlan> plans;
    private String title;
    private LocalDate startDate;
    private int nights;
    private int days;
    private String whereToStay;

    public DefaultTourPlanBuilder() {
        this.plans = new ArrayList<>();
        this.title = "";
        this.startDate = LocalDate.now();
        this.nights = 0;
        this.days = 0;
        whereToStay = "";
    }

    @Override
    public TourPlanBuilder title(String title) {
        this.title = title;
        return this;
    }

    @Override
    public TourPlanBuilder startDate(LocalDate startDate) {
        this.startDate = startDate;
        return this;
    }

    @Override
    public TourPlan build() {
        return new TourPlan(this.title, this.nights, this.days, this.startDate, this.whereToStay, this.plans);
    }

    @Override
    public TourPlanBuilder nightsAndDays(int nights, int days) {
        this.nights = nights;
        this.days = days;
        return this;
    }

    @Override
    public TourPlanBuilder whereToStay(String whereToStay) {
        this.whereToStay = whereToStay;
        return this;
    }

    @Override
    public TourPlanBuilder addPlan(int day, String plan) {
        this.plans.add(new DetailPlan(day, plan));
        return this;
    }
}

GithubRepository

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;
    }
}

Prototype 클라이언트 코드

class GithubIssueCloneTest {

    @Test
    public void clone_test() throws CloneNotSupportedException {
        GithubRepository repository = new GithubRepository();
        repository.setUser("kktrkkt");
        repository.setName("live-study");

        GithubIssue githubIssue = new GithubIssue(repository);
        githubIssue.setId(1);
        githubIssue.setTitle("1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.");

        GithubIssue clone = (GithubIssue) githubIssue.clone();

        assertTrue(clone != githubIssue);
        assertEquals(githubIssue, clone);
        assertEquals(githubIssue.getClass(), clone.getClass());
    }

}

프로토타입 패턴은 객체 생성비용이 큰 경우 효율적이다

단, 복제하는 과정이 복잡하다면 오히려 비용이 증가될 수 있다.

예제는 이곳 에서 확인하실수 있습니다.