프로토타입 (Prototype) 패턴

2 minute read

🔗 프로토타입 (Prototype) 패턴이란?

  • 프로토타입은 주로 실제 제품을 만들기에 앞서 대략적인 샘플 정도의 의미로 사용되는 단어이다.

  • 프로토타입 패턴은 객체를 생성하는 데 비용(시간과 자원)이 많이 들고, 비슷한 객체가 이미 있는 경우에 사용되는 생성 패턴 중 하나이다.

  • 프로토타입 패턴은 Original 객체를 clone() 메소드를 통해 새로운 객체에 복사하여 필요에 따라 수정하는 메커니즘을 제공한다.

  • 추상 팩토리 패턴과는 반대로 클라이언트 응용 프로그램 코드 내에서 객체 창조자(creator)를 서브클래스(subclass)하는 것을 피할 수 있게 해준다.

💎 프로토타입 패턴 구현시 주의 사항
  • 프로토타입 패턴 구현 시 java의 clone()을 이용하기 때문에 생성하고자 하는 객체에 clone에 대한 Override를 요구한다.
    • 이때 반드시 생성하고자 하는 객체의 클래스에서 clone()이 정의되어야 한다.
  • 패턴 구현 시 우선 clone() 메소드를 선언하는 추상 베이스 클래스를 하나 만든다.
    • 다형적 생성자 기능이 필요한 클래스가 있다면, 그것을 앞서 만든 클래스를 상속받게 한 후 clone() 메소드 내의 코드를 구현한다.
  • 얕은 복사 (Shallow Copy)로 할 지, 깊은 복사(Deep Copy)로 할 지에 대해서는 선택적으로 행하면 된다.

💎 Cloneable를 상속한 추상 베이스 클래스 - clone 선언 되어 있음

package CreationalPattern.PrototypePattern;

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

public class Employees implements Cloneable {

    private List<String> empList;

    public Employees() {
        empList = new ArrayList<>();
    }

    public Employees(List<String> empList) {
        this.empList = empList;
    }

    // DB 데이터를 조회하는것이라고 가정해보자.
    public void loadData() {
        empList.add("Pankaj");
        empList.add("Raj");
        empList.add("David");
        empList.add("Lisa");
    }

    public List<String> getEmpList() {
        return empList;
    }

    public void setEmpList(List<String> empList) {
        this.empList = empList;
    }

    @Override
    protected Employees clone() throws CloneNotSupportedException {
        List<String> temp = new ArrayList<>();
        for (String s : this.empList) {
            temp.add(s);
        }
        return new Employees(temp);
    }
}
  • 위 코드를 보면 clone() 메소드를 재정의하기 위해 Cloneable 인터페이스를 구현한 것을 확인할 수 있다.
    • 여기서 사용되는 clone()은 empList에 대하여 깊은 복사 (deep copy)를 실시한다.

💎 clone 실행 main 메소드

package CreationalPattern.PrototypePattern;

import java.util.List;

public class PrototypePatternTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        
        Employees emps = new Employees();
        emps.loadData();

        Employees cloneNew = (Employees) emps.clone();
        Employees cloneNew1 = (Employees) emps.clone();

        List<String> list = cloneNew.getEmpList();
        list.add("John");
        List<String> list1 = cloneNew1.getEmpList();
        list1.remove("Pankaj");

        //sout
        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
  • 위 코드에서 만약 Employees 클래스가 clone()을 제공하지 않았다면, loadData를 매번 호출하여 DB로 부터 데이터를 직접 가져와야 했을 것이고, 그로 인해 상당히 큰 비용이 발생했을 것이다.

  • 하지만 프로토타입을 사용한다면 1회의 DB 접근을 통해 가져온 데이터를 복사하여 사용한다면 이를 해결할 수 있다. (객체를 복사하는 것이 DB접근보다 훨씬 비용이 적다.)

Comments