OOP/Design Pattern

05. 프로토타입(Prototype) 패턴

지구우중 2023. 2. 13. 18:33

프로토타입(Prototype) 패턴: 생성패턴


 

 

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

 

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

 

보통 DB에서 데이터를 읽어와 인스턴스를 생성할 때나 요청을 보내서 가져온 데이터로 인스턴스를 만들어야 하는 경우 오래시간과 큰 리소스가 필요하다. 때문에 데이터를 복제해서 새로운 인스턴스를 만들고 원하는 값만 일부 변경하여 사용한다.

 

프로토타입패턴은 복사를 위해 자바에서 제공하는 clone메소드를 사용할 수 있다.

자바에서 제공하는 clone메소드를 사용하기 때문에 생성하고자 하는 객체에 clone에 대한 Override를 요구한다. 이때, 주의할 점은 반드시 생성하고자 하는 객체의 클래스에서 clone메소드가 정의되어있어야한다.

프로토타입 패턴의 장단점

장점

  • 복잡한 객체를 만드는 과정을 숨길 수 있다.
  • 기존 객체를 복제하는 과정이 새 인스턴스를 만드는 것보다 비용(시간 또는 메모리)적인 면에서 효율적일 수 있다.
  • 추상적인 타입을 리턴할 수 있다.

단점

  • 복잡한 객체를 만드는 과정 자체가 복잡할 수 있다. (특히 순환 참조가 있는 경우)

 

ModelMapper

서로 다른 클래스의 값을 한 번에 복사하게 도와주는 라이브러리로,어떤 Object (Source Object) 에 있는 필드 값들을 자동으로 원하는 Object (Destination Object) 에 매핑 시켜주는 라이브러리다.
implementation 'org.modelmapper:modelmapper:2.4.2'

자바에서 제공해주는 clone()은 문제점이 많기 때문에 자바 프로젝트를 다룬다면 의존성을 추가해서 ModelMapper 라이브러리를 사용하는 것이 더 효율적이라는 얘기가 많다. 명확한 프로토타입 패턴이라 말할 수는 없지만, 비슷한 역할을 하기에 ModelMapper 라이브러리를 사용할 수 있다.

 

 

프로토타입 패턴의 예시

Player

import lombok.Getter;
import lombok.Setter;

@Setter @Getter
public class Player implements Cloneable{
    private String name;
    private int HP;
    private int MP;
    private Weapon weapon;

    @Override
    public Player clone() throws CloneNotSupportedException{
        // 아래와 같이 기존 메서드를 활용하면, 필드로 선언된 인스턴스가 얕은 복사가 되어, 원본객체에 영향을 미친다.
        //return (Player) super.clone();
        
        Weapon weapon = new Weapon(this.weapon.getName());
        Player player = new Player();
        
        player.setName(this.name);
        player.setHP(this.HP);
        player.setMP(this.MP);
        player.setWeapon(weapon);

        return player;
    }
}

* colne() 메서드를 그대로 쓰면 얕은 복사가 된다. 때문에 주석처리가 된 방식으로 clone하는 것은 바람직하지 않다.

* setter은 되도록 지양해야한다. 무분별한 setter 사용은 이 데이터가 왜 변경되는지 알 수 없기 때문에 의미있는 메서드 이름으로 사용해야한다. 하지만 나는 test니까 그냥 썼음...주저리주저ㅏ리...

 

Weapon

import lombok.Getter;
import lombok.Setter;

@Setter @Getter
public class Weapon {
    private String name;
    Weapon(String name){
        this.name = name;
    }
}

Client

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException{
        Player player = new Player();
        player.setName("안녕");
        player.setHP(50);
        player.setMP(100);
        player.setWeapon(new Weapon("금빛칼"));

        Player clone = player.clone();
        clone.setName("닉넴을바꿀게");
        clone.getWeapon().setName("양날도끼");
        System.out.println(player.getName() + "  " + clone.getName());
    }
}

 

Reference

https://kingchan223.tistory.com/295