본문 바로가기
Design Pattern/생성 패턴(Creational patterns)

Prototype Pattern, 프로토타입 패턴

by codeyaki 2023. 7. 11.
반응형

프로토 타입 패턴이란?

  • 객체를 생성할 때 기존 객체를 복제하여 새로운 객체를 생성하는 방법을 제공하는 패턴이다. 이를 통해서 객체의 복잡한 생성 과정을 피하고, 기존 객체의 상태를 유지하며 새로운 객체를 생성할 수 있게 된다.
  • 프로그래밍에서 변경이 일어나는 부분을 캡슐화한다는 따른다.

왜 사용하나요?

  • 객체 생성 과정이 복잡하거나 시간이 많이 걸릴 경우, 기존 객체를 복제하여 새로운 객체를 생성하는 것이 효율적이기 때문이다.
  • 객체의 클래스에 종속되지 않고, 복제를 통해 동적으로 객체를 생성할 수 있다.
  • 객체의 상태를 유지한 채 다양한 상태의 객체를 생성할 수 있다.

언제 사용하나요?

  • 객체 생성 비용이 크고 유사한 객체를 자주 생성해야 할 때
  • 객체의 클래스 계통이 복잡하고 변경이 빈번하게 일어날 때

문제점

  • 객체의 복제 과정이 복잡해질 수 있다. 객체의 내부 상태에 따라 복제의 어려움이 발생할 수 있다. (순환 참조)
  • 프로토타입 객체가 변경되면 생성된 복제 객체들도 영향을 받을 수 있다.

구현 방법(자바)

1.  Java 표준 인터페이스인 Cloneable을 사용하여 구현하기

자바에서는 clone() 메서드를 가진 인터페이스가 구현되어 있다. java.lang에 속해있어 따로 import를 사용하지 않아도 사용할 수 있다.

  • Prototype
public class Prototype implements Cloneable {
    private String name;

    public Prototype(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}
  • Main 메서드
public class Main {
    public static void main(String[] args) {
        System.out.println("=== Clonable 사용 예시 ===");
        Prototype prototype = new Prototype("난 프로토 타입이지롱");
        System.out.println("prototype = " + prototype);
        Prototype clone1 = prototype.clone();
        System.out.println("clone1 = " + clone1);

        /* 필드 변경하기 */
        Prototype clone2 = prototype.clone();
        clone2.setName("난 특별해");
        System.out.println("clone2 = " + clone2);

    }
}

실행하면 아래와 같이 나온다.

 

2.  Cloneable 인터페이스를 사용하지 않고 구현하기

  • Pizza 클래스 만들기 (Clone 할 수 있는 클래스)
public abstract class Pizza {
    private String name;
    private String size;
    private int price;

    public Pizza() {
    }

    public Pizza(String name, String size, int price) {
        this.name = name;
        this.size = size;
        this.price = price;
    }

    public Pizza(Pizza pizza) {
        this.name = pizza.getName();
        this.size = pizza.getSize();
        this.price = pizza.getPrice();
    }

    public abstract Pizza clone();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSize() {
        return size;
    }

    public void setSize(String size) {
        this.size = size;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Pizza)) return false;
        Pizza pizza2 = (Pizza) o;
        return this.name.equals(pizza2.name) && this.size.equals(pizza2.size) && this.price == pizza2.price;

    }

    @Override
    public String toString() {
        return "Pizza{" +
                "name='" + name + '\'' +
                ", size='" + size + '\'' +
                ", price=" + price +
                '}';
    }
}
  • Pizza 클래스를 상속받은 BulgogiPizza 클래스
public class BulgogiPizza extends Pizza {
    private int bulgogiCount;

    public BulgogiPizza() {
    }

    public int getBulgogiCount() {
        return bulgogiCount;
    }

    public void setBulgogiCount(int bulgogiCount) {
        this.bulgogiCount = bulgogiCount;
    }

    public BulgogiPizza(BulgogiPizza bulgogiPizza) {
        super(bulgogiPizza);
        if (bulgogiPizza != null) {
            this.bulgogiCount = bulgogiPizza.bulgogiCount;
        }
    }

    @Override
    public BulgogiPizza clone() {
        return new BulgogiPizza(this);
    }

    @Override
    public String toString() {
        return "BulgogiPizza{" +
                "name=" + this.getName() +
                ", size=" + this.getSize() +
                ", price" + this.getPrice() +
                ", bulgogiCount=" + bulgogiCount +
                '}';
    }
}
  • Main 클래스
public class Main {
    public static void main(String[] args) {
        /* Cloneable 객체를 사용하지 않았을 때 */
        System.out.println("=== Cloneable 객체를 사용하지 않은 예시 ===");
        BulgogiPizza pizza = new BulgogiPizza();
        pizza.setName("불고기 피자");
        pizza.setSize("large");
        pizza.setPrice(24000);
        pizza.setBulgogiCount(50);
        System.out.println("pizza = " + pizza);

        /* 불고기 피자 객체 복사 */
        BulgogiPizza BulgogiPizzaClone = pizza.clone();
        BulgogiPizzaClone.setSize("medium"); // 원하는 필드만 변경하여 사용
        System.out.println("BulgogiPizzaClone = " + BulgogiPizzaClone);

    }
}

실행하면 마찬가지로 아래와 같이 나온다.

 

반응형