개발자의 무지개

프로토타입 패턴 (Prototype Pattern) 본문

소프트웨어 아키텍처/디자인패턴

프로토타입 패턴 (Prototype Pattern)

파란막대 2022. 7. 9. 12:17

개념

프로토타입 패턴은 생성 패턴의 한 종류로,  서브클래스의 객체를 복사할 경우 의존관계를 가지지 않고도 객체를 복사할 수 있게 한다.

서브클래스는 부모인 Prototype클래스를 상속받아 clone 을 구현하여, Prototype 타입의 객체에게 복제 기능을 제공한다.

 

 

상황

이어폰 기본 속성은 가격과 색상이 있고, 유선이어폰은 케이블길이, 무선이어폰은 배터리용량 속성을 각 각 가지고 있다.

유선과 무선 이어폰에 대한 제품설명을 출력하는 프로그램을 만들어보자.

 

    public abstract class Earphone {
        protected int price;
        protected String color;

        public Earphone(int price, String color) {
            this.price = price;
            this.color = color;
        }

        public abstract String description();
    }

    public class wiredEarphone extends Earphone{
        int cableLength;

        public wiredEarphone(int price, String color, int cableLength) {
            super(price, color);
            this.cableLength = cableLength;
        }

        @Override
        public String description() {
            return String.format("Price : %d, Color : %s, Cable length : %d \n",
                    price, color, cableLength);
        }
    }

    public class wirelessEarphone extends Earphone {
        int batterySize;

        public wirelessEarphone (int price, String color, int batterySize) {
            super(price, color);
            this.batterySize = batterySize;
        }

        @Override
        public String description() {
            return String.format("Price : %d, Color : %s, Battery size : %d \n",
                    price, color, batterySize);
        }

    }

Earphone 클래스는 기본 속성인 price와 color를 멤버로 가지고,  discription 라는 추상 메서드를 선언함으로 서브클래스에서 제품설명을 구현하게 하였다.

Earphone 을 상속받은 WiredEarphone, WirelessEarphone은 각자의 discription를 구현하여 서로 다른 제품 설명을 출력하게 했다.

 

이제 이어폰 별로 제품 설명을 출력해보자.

    Earphone earphone1 = new WiredEarphone(1000, "red", 20);		
    Earphone earphone2 = new WirelessEarphone(1000, "blue", 3000);

    System.out.println("[earphone 1] " + earphone1.description());
    System.out.println("[earphone 2] " + earphone2.description());



    /* 출력 결과 
    * [earphone 1] Price : 1000, Color : red, Cable length : 20 
    * 
    * [earphone 2] Price : 1000, Color : blue, Battery size : 3000 
    */

이어폰은 earphone1와 earphone2의 인스턴스를 만들어 결과를 출력하였고, 의도대로 각기 다른 정보가 출력되었다.

여기서 earphone1와 earphone2를 earphone3와 earphone4로 복제해야하는 요구사항이 들어오자 문제가 발생했다.

 

첫번째 문제는 Earphone의 속성이 은닉화되어 있어 외부에서 접근이 불가능하기에, 속성값을 추출할 수가 없어 Earphone과 서브클래스를 수정해야만 한다.

두번째 문제는 WiredEarphone, WirelessEarphone을 복제하려면 추상화가 제거되어 의존관계가 만들어지게 된다.

(쉽게 얘기하면 Earphone 이 아닌 실제타입 WiredEarphone, WirelessEarphone로의 변환이 필요하다.)

 

이제 프로토타입 패턴을 적용하여 문제를 해결해보자.

프로토타입 패턴 적용

    public abstract class Earphone {
        protected int price;
        protected String color;

        public Earphone(int price, String color) {
            this.price = price;
            this.color = color;
        }


        public abstract String description();

        //clone 추상메서드 추가
        public abstract Earphone clone();
    }


    public class WiredEarphone extends Earphone{
        int cableLength;

        public WiredEarphone(int price, String color, int cableLength) {
            super(price, color);
            this.cableLength = cableLength;
        }

        @Override
        public String description() {
            return String.format("Price : %d, Color : %s, Cable length : %d \n",
                    price, color, cableLength);
        }

        @Override
        public Earphone clone() {
            WiredEarphone wiredEarphone = new WiredEarphone(this.price, this.color, this.cableLength);
            return wiredEarphone;
        }

    }

    public class WirelessEarphone extends Earphone {
        int batterySize;

        public WirelessEarphone (int price, String color, int batterySize) {
            super(price, color);
            this.batterySize = batterySize;
        }

        @Override
        public String description() {
            return String.format("Price : %d, Color : %s, Battery size : %d \n",
                    price, color, batterySize);
        }

        @Override
        public Earphone clone() {
            WirelessEarphone wirelessEarphone = new WirelessEarphone(this.price, this.color, this.batterySize);
            return wirelessEarphone;
        }
    }

Earphone 클래스에서 clone 메서드를 선언하여 서브클래스에서 구현하게 만들었다.

WiredEarphone과 WirelessEarphone 클래스는 clone 메서드에서 인스턴스를 추가로 생성하여 리턴한다.

 

이제 사용부 코드를 보면 clone 메서드를 통해 복제코드 작성없이,  동일한 속성의 다른 인스턴스를 가지게 되었다.

    Earphone earphone1;	
    Earphone earphone2;

    /* 
    * 유선 및 무선 이어폰 객체를 생성한다.
    */
    earphone1 = new WiredEarphone(1000, "red", 20);
    earphone2 = new WirelessEarphone(1000, "blue", 3000);

    //원본 타입으로 unboxing하지 않더라도 객체를 복제할 수 있다.
    Earphone earphone3 = earphone1.clone();
    Earphone earphone4 = earphone2.clone();

    System.out.println("[earphone 1] " + earphone1.description());
    System.out.println("[earphone 2] " + earphone2.description());
    System.out.println("[earphone 3] " + earphone3.description());
    System.out.println("[earphone 4] " + earphone4.description());

    /* 실행 결과 
    * [earphone 1] Price : 1000, Color : red, Cable length : 20 
    * 
    * [earphone 2] Price : 1000, Color : blue, Battery size : 3000 
    * 
    * [earphone 3] Price : 1000, Color : red, Cable length : 20 
    * 
    * [earphone 4] Price : 1000, Color : blue, Battery size : 3000 
    */

 

 


■ 참고사이트

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

https://developpaper.com/5-design-pattern-prototype-pattern-2/