[패캠강의] 프로토 타입 패턴

2022. 1. 12. 20:59디자인 패턴

[패캠강의] 프로토 타입 패턴

복잡한 클래스의 인스턴스를 생성할 때 하나의 견본(prototype)을 만들어 초기화해두고 이를 복제해서 객체를 사용하는 방법입니다. (Java clone() 메서드라고 생각하시면 됩니다.)

예제코드를 보면 바로 이해할 수 있을 겁니다.

주의할 점은 Mark interface(override해야할 메서드가 없이 특성만 알려주는 인터페이스) Cloneable깊은 복사입니다. 참고로 Arrays.copyOf() 메서드도 깊은 복사를 채택합니다.

    //Arrays.copyOf() 메서드 docs, 새로운 배열을 만들어서 System.arraycopy 해줍니다.
    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

package com.baekho.design.pattern.prototype;

import java.util.ArrayList;
import java.util.List;

class Book {

    private String author;
    private String title;

    public Book(String author, String title) {
        this.author = author;
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String toString() {
        return "(" +  author + ", " + title + ")";
    }
}

class BookShelf implements Cloneable { //함부로 외부에서 변경해선 안되는 객체, mark 인터페이스 Cloneable를 사용해줍니다.

    private List<Book> shelf;

    public BookShelf() {
        shelf = new ArrayList<>();
    }

    public void add(Book book) {
        if (book == null) {
            throw new NullPointerException("Book is null!");
        }
        shelf.add(book);
    }

    public List<Book> getShelf() {
        return shelf;
    }

    public void setShelf(List<Book> shelf) {
        this.shelf = shelf;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {

        //얕은 복사
//        return super.clone();
        //깊은 복사
        BookShelf another = new BookShelf();
        this.getShelf().forEach(b -> another.add(new Book(b.getAuthor(), b.getTitle())));

        return another;
    }

    public String toString() {
        return shelf.toString();
    }
}


public class PrototypeTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        BookShelf bookShelf = new BookShelf();

        bookShelf.add(new Book("김승호","돈의속성"));
        bookShelf.add(new Book("무라카미 하루키","해변의 카프카"));
        bookShelf.add(new Book("장 폴 사르트르","존재와 무1"));

        System.out.println(bookShelf);

        BookShelf anotherBookShelf = (BookShelf) bookShelf.clone();
        System.out.println("anotherBookShelf:: " +  anotherBookShelf);

        bookShelf.getShelf().get(0).setAuthor("한강");
        bookShelf.getShelf().get(0).setTitle("채식주의자");

        //주소를 복제해주는 얕은복사였기 때문에 같은 주소를 가리키고 있습니다.
        System.out.println(bookShelf);
        System.out.println("anotherBookShelf:: " +  anotherBookShelf);
    }
}

/* 출력:
[(김승호, 돈의속성), (무라카미 하루키, 해변의 카프카), (장 폴 사르트르, 존재와 무1)]
anotherBookShelf:: [(김승호, 돈의속성), (무라카미 하루키, 해변의 카프카), (장 폴 사르트르, 존재와 무1)]

[(한강, 채식주의자), (무라카미 하루키, 해변의 카프카), (장 폴 사르트르, 존재와 무1)]
anotherBookShelf:: [(김승호, 돈의속성), (무라카미 하루키, 해변의 카프카), (장 폴 사르트르, 존재와 무1)]
 */

참고자료