본문 바로가기
디자인 패턴

자바(JAVA) - 프로토타입(Prototype) 패턴

by Hyeongjun_Ham 2023. 11. 20.

- 자바(JAVA) - 프로토타입(Frototype) 패턴

 

1. 의도

원형이 되는 인스턴스를 사용하여 생성할 객체의 종류를 명시하고, 이렇게 만든 견본을 복사해서 새로운 객체를 생성

 

즉, 기존 인스턴스를 복제하여 새로운 인스턴스를 만드는 것

 

2. 용도

객체를 생성하는데 비용이 많이 들고, 비슷한 객체가 이미 있는 경우에 사용

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

 

3. UML

4. 구현

- 적용 전

public class Member {

    private final String name;
    private final String address;
    private final BasicItem basicItem;

    public Member(String name, String address, BasicItem basicItem) {
        this.name = name;
        this.address = address;
        this.basicItem = basicItem;
    }

    public void desc() {
        System.out.println("이름 : " + name);
        System.out.println("주소 : " + address);
        System.out.println("지원 아이템 : " + basicItem.getBag());
        System.out.println("가방 이름 : " + basicItem.getBagInfo().getBagName());
    }
}

=======================================================================
public class BagInfo {

    private String bagName;

    public String getBagName() {
        return bagName;
    }

    public void setBagName(String bagName) {
        this.bagName = bagName;
    }
}

=======================================================================
public class BasicItem {

    private final BagInfo bagInfo;

    private final List<String> bag;

    public BasicItem(BagInfo bagInfo) {
        this.bagInfo = bagInfo;
        this.bag = new ArrayList<>();
    }

    public BagInfo getBagInfo() {
        return bagInfo;
    }

    public void add(String item) {
        bag.add(item);
    }
    public void remove(String item) {
        bag.remove(item);
    }

    public List<String> getBag() {
        return bag;
    }
}

=======================================================================
public class Client {
    public static void main(String[] args) {

        BagInfo bagInfo = new BagInfo();
        bagInfo.setBagName("기본");

        BasicItem basicItems = new BasicItem(bagInfo);
        basicItems.add("책상");
        basicItems.add("의자");
        basicItems.add("컴퓨터");
        basicItems.add("키보드");
        basicItems.add("등등");

        Member member = new Member("멤버1", "강남", basicItems);
        member.desc();
        System.out.println("===============================");

        BagInfo bagInfo2 = new BagInfo();
        bagInfo2.setBagName("기본");

        BasicItem basicItems2 = new BasicItem(bagInfo2);
        basicItems2.add("책상");
        basicItems2.add("의자");
        basicItems2.add("컴퓨터");
        basicItems2.add("등등");

        Member member2 = new Member("철수", "서울", basicItems2);
        member2.desc();
    }
}
/*
이름 : 멤버1
주소 : 강남
지원 아이템 : [책상, 의자, 컴퓨터, 키보드, 등등]
가방 이름 : 기본
===============================
이름 : 철수
주소 : 서울
지원 아이템 : [책상, 의자, 컴퓨터, 등등]
가방 이름 : 기본
*/

 

- 적용 후

public class BasicItem implements Cloneable{

    private final BagInfo bagInfo;
    private final List<String> bag;

    public BasicItem(BagInfo bagInfo) {
        this.bagInfo = bagInfo;
        this.bag = new ArrayList<>();
    }

    public BagInfo getBagInfo() {
        return bagInfo;
    }

    public void add(String item) {
        bag.add(item);
    }
    public void remove(String item) {
        bag.remove(item);
    }

    public List<String> getBag() {
        return bag;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

===================================================================

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {

        BagInfo bagInfo = new BagInfo();
        bagInfo.setBagName("기본");
        BasicItem basicItems = new BasicItem(bagInfo);
        basicItems.add("책상");
        basicItems.add("의자");
        basicItems.add("컴퓨터");
        basicItems.add("키보드");
        basicItems.add("등등");

        Member member = new Member("멤버1", "강남", basicItems);
        member.desc();
        System.out.println("===============================");

        BasicItem basicItems2 = (BasicItem) basicItems.clone();

        System.out.println(basicItems != basicItems2);
        System.out.println(basicItems.getClass() == basicItems2.getClass());
        System.out.println(basicItems.getBagInfo() == basicItems2.getBagInfo());

        basicItems2.remove("키보드");

        bagInfo.setBagName("바뀜");

        Member newMember = new Member("철수", "서울", basicItems2);
        newMember.desc();
    }
}
/*
이름 : 멤버1
주소 : 강남
지원 아이템 : [책상, 의자, 컴퓨터, 키보드, 등등]
가방 이름 : 기본
===============================
이름 : 철수
주소 : 서울
지원 아이템 : [책상, 의자, 컴퓨터, 등등]
가방 이름 : 바뀜
true
true
true
*/

 

문제점은 bagInfo.setBagName("바뀜"); 로 주입 받은 객체가 바뀐게 적용 됨. (얕은 복사)

@Override
    protected Object clone() throws CloneNotSupportedException {
        BagInfo bagInfo = new BagInfo();
        bagInfo.setBagName(this.bagInfo.getBagName());
        BasicItem basicItems = new BasicItem(bagInfo);
        basicItems.add("책상");
        basicItems.add("의자");
        basicItems.add("컴퓨터");
        basicItems.add("키보드");
        basicItems.add("등등");
        return basicItems;
    }

/*
이름 : 멤버1
주소 : 강남
지원 아이템 : [책상, 의자, 컴퓨터, 키보드, 등등]
가방 이름 : 기본
===============================
이름 : 철수
주소 : 서울
지원 아이템 : [책상, 의자, 컴퓨터, 등등]
가방 이름 : 기본
true
true
false
*/

clone() 을 재 정의하여 깊은 복사로 바꾼다.

 

5. 패턴의 장단점

  • 장점
    • 복잡한 객체를 만드는 과정을 숨길 수 있다.
    • 기존 객체를 복제하는 과정이 새 인스턴스를 만드는 것보다 비용(시간 or 메모리)적인 면에서 효율적일 수 있다.
    • 추상적인 타입을 리턴할 수 있다.
  • 단점
    • 복제한 객체를 만드는 과정 자체가 복잡할 수 있다. (특히, 순환참조가 있는 경우)

 

출처 :

https://refactoring.guru/design-patterns/prototype

 

Prototype

/ Design Patterns / Creational Patterns Prototype Also known as: Clone Intent Prototype is a creational design pattern that lets you copy existing objects without making your code dependent on their classes. Problem Say you have an object, and you want to

refactoring.guru