Prototype Pattern

Original 객체를 새로운 객체에 복사하여 필요에 따라 수정하는 메커니즘을 제공

제목 없음

  • Prototype : 인스턴스를 복사하여 새로운 인스턴스를 만들기 위한 메소드 결정
  • ConcretePrototype : 인스턴스 복사해서 새로운 인스턴스 만드는 메소드 구현
  • Client : 인스턴스 복사 메소드를 사용해서 새로운 인스턴스 생성


  • 복사를 위하여 Java에서 제공하는 clone() 사용
    • 생성하고자 하는 객체의 클래스에서 clone() 재정의
  • 객체를 생성하는 데 비용(시간과 자원)이 많이 들고, 비슷한 객체가 이미 있는 경우에 사용되는 생성 패턴 중 하나
    • ex)
      • 데이터 베이스에서 데이터를 읽어와서 인스턴스를 생성
      • http 요청을 보내서 가져온 데이터로 인스턴스를 만들어야 하는 경우
    • 객체를 복사하는 것이 네트워크 접근이나 DB 접근보다 훨씬 비용이 적음


Example

  • DB로부터 가져오는 객체
    → 프로그램에서 수차례 수정을 해야하는 요구사항이 있는 경우
    • 매번 new 라는 키워드를 통해 객체를 생성하여 DB로부터 항상 모든 데이터를 가져오면?
      ⇒ DB로 접근해서 데이터를 가져오는 행위는 비용이 큼


⇒ 한 번 DB에 접근하여 데이터를 가져온 객체를 필요에 따라 새로운 객체에 복사하여 데이터 수정 작업을 하는 것이 더 좋은 방법


  • 이때 객체의 복사를 얕은 복사(shallow copy)로 할지, 깊은 복사(deep copy)로 할지는 선택적으로
    • 기본적으로 Object class의 clone()은 얕은복사
      → 깊은복사 위해서는 재정의하기


  • Employees class(직원정보를 DB에서 가져온다고 가정)
public class Employees implements Cloneable{
 
    private List<String> empList;
	
    public Employees(){
        empList = new ArrayList<String>();
    }
	
    public Employees(List<String> list){
        this.empList=list;
    }
    
    public void loadData(){
        empList.add("Pankaj");
        empList.add("Raj");
        empList.add("David");
        empList.add("Lisa");
    }
	
    public List<String> getEmpList() {
        return empList;
    }
 
    @Override
    public Object clone() throws CloneNotSupportedException{
        List<String> temp = new ArrayList<String>();
        for(String s : this.empList){
            temp.add(s);
        }
        return new Employees(temp);
    }
	
}
public class PrototypePatternTest {
 
    public static void main(String[] args) throws CloneNotSupportedException {
        Employees emps = new Employees();
        emps.loadData();
		
        Employees empsNew = (Employees) emps.clone();
        Employees empsNew1 = (Employees) emps.clone();
        List<String> list = empsNew.getEmpList();
        list.add("John");
        List<String> list1 = empsNew1.getEmpList();
        list1.remove("Pankaj");
		
        System.out.println("emps List: "+emps.getEmpList());
        System.out.println("empsNew List: "+list);
        System.out.println("empsNew1 List: "+list1);
    }
 
}
emps List: [Pankaj, Raj, David, Lisa]
empsNew List: [Pankaj, Raj, David, Lisa, John]
empsNew1 List: [Raj, David, Lisa]
  • emps.clone() 을 통해 empList에 대하여 copy(deep) 실시 ⇒ 1회의 DB 접근을 통해 가져온 데이터를 복사하여 사용 → 객체 생성의 비용을 줄일 수 있음

  • 만약 DB로부터 매번 employee 리스트를 직접 가져왔다면?
    → 그로 인해 DB접근으로 인한 큰 비용(시간, 리소스) 발생


참고)
Model Mapper : 객체의 값들을 다른 객체로 복사해주는 편리한 라이브러리


참고)

  • shallow copy : 하나의 객체의 주소값을 복사
public static void main(String[] args) {
  Cat navi = new Cat("navi");

  Cat yo = navi;
  yo.chgName("yo");

  System.out.println(navi.getName());
  System.out.println(yo.getName());
}
yo
yo


  • deep copy : 하나의 객체의 값들을 복사
public class Cat implements Cloneable{
    ...

     public Cat copy() throws CloneNotSupportedException {
    Cat ret = (Cat)this.clone();
    return ret;
  }
}

public static void main(String[] args) throws CloneNotSupportedException {
  Cat navi = new Cat("navi");

  Cat yo = navi.copy();
  yo.chgName("yo");

  System.out.println(navi.getName());
  System.out.println(yo.getName());
}
navi
yo



Reference
https://readystory.tistory.com/122
https://m.blog.naver.com/gleblu4422/222675395264
https://kingchan223.tistory.com/295
https://lee1535.tistory.com/76

업데이트: