# Prototype Pattern 덱스 린지어스(Dex Ringeus)는 사용자들이 회원 등록 양식에 불편함을 느끼는 것을 발견했다. 이것을 좀 더 편리하게 만들어야 한다. 페드로: 등록 양식에 무슨 문제가 있나요? 이브: 사용자들이 입력할 항목들이 너무 많아서 짜증날 정도예요. 페드로: 예를 들면요? 이브: 예를 들면 체중 항목이예요. 여성 사용자들의 90%가 그런 항목을 보면 짜증을 낼 거예요. 페드로: 하지만 이 항목은 우리의 분석 시스템에 중요해요. 이 항목 값에 근거해 음식과 옷을 추천해 주고 있거든요. 이브: 그러면 이 항목을 필수 입력 항목에서 제외하기로 하죠. 이 항목 값이 입력되지 않으면 기본값을 넣어 주고요. 페드로: 60kg이면 적당할까요? 디브: 그런 것 같아요. 페드로: 알았어요. 2분만 기다려 주세요. 두 시간이 흐른 뒤 페드로: 모든 항목이 기본값으로 채워진 등록 양식 프로토타입을 사용해요. 사용자가 양식 작성을 끝냈을 때, 기본값들을 변경하면 돼요. 이브: 좋습니다. 페드로: 여기에 표준 등록 양식이 있어요. clone() 메소드에서는 프로토타입을 사용하고 있고요. public class RegistrationForm implements Cloneable { private String name = "Zed"; private String email = "zzzed@gmail.com"; private Date dateOfBirth = new Date(1970, 1, 1); private int weight = 60; private Gender gender = Gender.MALE; private Status status = Status.SINGLE; private List children = Arrays.asList(new Child(Gender.FEMALE)); private double monthSalary = 1000; private List favouriteBrands = Arrays.asList("Adidas", "GAP"); // few hundreds more properties @Override protected RegistrationForm clone() throws CloneNotSupportedException { RegistrationForm prototyped = new RegistrationForm(); prototyped.name = name; prototyped.email = email; prototyped.dateOfBirth = (Date)dateOfBirth.clone(); prototyped.weight = weight; prototyped.status = status; List childrenCopy = new ArrayList(); for (Child c : children) { childrenCopy.add(c.clone()); } prototyped.children = childrenCopy; prototyped.monthSalary = monthSalary; List brandsCopy = new ArrayList(); for (String s : favouriteBrands) { brandsCopy.add(s); } prototyped.favouriteBrands = brandsCopy; return prototyped; } } 페드로: 사용자를 만들 때마다, clone()을 호출해서 기본값을 바꿉니다. 이브: 끔직하네요! 가변 자료형의 세상에서는 동일한 값의 객체를 새로 생성하려면 clone()이 필요해요. 난점은 깊은 복사를 해야 한다는 것입니다. 단순히 레퍼런스를 복사하면 안되고, 재귀적으로 내부의 객체들을 clone() 해야만 하지요. 그런데 그 객체들 중의 일부에 clone() 메소드가 없으면 어떻게 될까요? 페드로: 그게 바로 문제인데, 이 패턴은 그 문제를 해결해 주죠. 이브: 제가 보기에, 새로운 객체를 추가해 줄 때마다 clone 메소드를 구현해 주어야만 한다면, 그것은 제대로 된 해결책이라고 보기 힘들다고 생각해요. 페드로: 클로저로는 이런 문제를 어떻게 피할 수 있죠? 이브: 클로저는 불변 자료구조를 제공해요. 그것이 전부예요. 페드로: 불변 자료구조로 프로토타입 문제를 어떻게 해결한다는 거죠? 이브: 객체를 변경할 때마다, 새로운 불변 객체를 얻게 되요. 그래서 예전 객체는 변경되지 않지요. 불변 자료형의 세상에서는 프로토타입 패턴이 필요 없어요. (def registration-prototype {:name "Zed" :email "zzzed@gmail.com" :date-of-birth "1970-01-01" :weight 60 :gender :male :status :single :children [{:gender :female}] :month-salary 1000 :brands ["Adidas" "GAP"]}) ;; return new object (assoc registration-prototype :name "Mia Vallace" :email "tomato@gmail.com" :weight 52 :gender :female :month-salary 0) 페드로: 훌륭하네요! 하지만 그런 식으로는 성능에 영향을 미치지 않을까요? 새로운 값을 추가할 때마다 수백만 개의 데이터를 복사하려면 꽤 시간이 걸리지 않나요? 이브: 아니, 그렇지 않아요. 구글에 가서 [[존속 데이터 구조]] (persistent data structures)와 [[구조 공유]] (structural sharing)에 관해 검색해 보세요. 페드로: 고마워요.