Prototype Pattern

1445664805_web-code

1.개요

JAVA에서 어떠한 인스턴스를 생성하기 위해서 우리는 ‘new’ 키워드를 사용하여 클래스의 이름을 지정하여 생성 한다. 예를 들어 문자열 ‘String’ 클래스의 인스턴스 ‘text’를 생성하기 위해선 다음과 같이 사용하곤 한다.

String text = new String();

하지만 이번에 사용할 ‘Prototype’ 패턴은 어떠한 클래스로부터 인스턴스를 만드는것이 아니라 인스턴스를 복사하여 새로운 인스턴스를 만드는 것 이다. 이렇게 인스턴스를 new하는게 아닌 clone()하여 만드는 상황은 여러가지가 있겠지만 정리를 하면 다음과 같다고 할 수 있다.

  • 종류가 너무 많아 클래스로 정리 되지 않음. 
    •  취급하는 객체의 종류가 너무 많아서, 각각의 객체를 별도의 클래스로 일일히 만들어서 다수의 java 소스 파일을 만들어야 할 때.
  • 클래스로부터 인스턴스 생성이 어려운 경우. 
    • 생성하고 싶은 인스턴스가 복잡한 작업을 거쳐 만들어지기 때문에 클래스로부터 만들기가 너무 어려운 경우.
    • 예를 들어 사용자가 직접 조작하여 만들어지는 인스턴스를 프로그래밍으로 만드는건 곤란하다. 사용자의 조작으로 만들어진 인스턴스를 다시 만들고 싶은 경우에는 지금 만든 인스턴스를 일단 저장하고 만들고 싶은 경우에 그것을 복사 한다.
  • framework와 생성할 인스턴스를 분리하려고 하는 경우.
    • 인스턴스를 생성했을때 framework에 의존적이지 않게 만들고 싶은 경우 이다.
    • 클래스 이름을 지정해서 인스턴스를 만드는게 아니라 이미 ‘prototype’이 되는 인스턴스를 등록하고, 그 인스턴스를 복사하여 새로운 인스턴스를 만들어 내는 것 이다.

인스턴스로부터 다른 인스턴스를 새로 생성해 낸 다는 것은 복사기의 개념과 비슷하다. 원래의 서류를 어떻게 만들었냐 보다든 이미 작성된 문서 서류를 복사기를 이용해서 똑같은 문서로 새로 복사해서 몇장이라도 만드는 것 이다.

이번 패턴에서 보여지는 ‘prototype’이라고 불리는 ‘원형’ 인스턴스를 미리 만들고, 이 인스턴스를 복사 (clone)하여 여러개의 인스턴스를 다루는 패턴을 알아 볼 것이다.

 

2. 예제 및 설명

Prototype 패턴의 예제 프로그램은 다음과 같다. 입력받은 문자열을 테두리 선 글자로 감싸거나, 밑줄 글자를 표시하는 간단한 프로그램 이다.

pp_0

 

Product : 추상 메소드 use()와 createClone()이 선언된 인터페이스

product 인터페이스는 java.lang.Cloneable 인터페이스를 상속하고 있는 복제 가능한 인터페이스 이다. 이 인터페이스를 구현하는 클래스는 clone() 메소드를 이용하여 자동으로 인스턴스를 복제 할 수 있다.

use() : 만들어진(복사된) 인스턴스를 ‘사용’ 하기 위한 메소드 이다. 이 ‘사용’이라고 하는 것은 인터페이스를 상속받아 구현한 자식 클래스에서 다루게 될 것이다. 이 예제에서는 텍스트를 출력 하는 내용이 될 것이다.

createClone() : 인스턴스를 복제하는 메소드.

 

Manager : createClone() 메소드를 이용하여 인스턴스를 복제하는 클래스

Manaager 클래스는 Product인터페이스를 사용해서 인터페이스의 복제를 실행하는 클래스 이다. showcase맵은 인스턴스의 ‘이름’과 ‘인스턴스’의 대응 관계를 HashMap으로 표현 한다.

register() : 제품의 이름인 name과 Product인터페이스가 주어지면 그 한 쌍을 showcase에 저장 한다. 입력받는 proto는 정확히 어떤 객체인지는 모르지만 확실한 것은 Product 인터페이스를 구현한 객체인 것은 알 수 있다.

register()메소드에서 어떠한 정확한 클래스 객체를 변수로 받는지 지명하지 않은것에 주의 하자. 만약 여기에 뒤에 나올 ‘MessageBox’클래스나 ‘UnderlinePen’클래스의 이름이 나오지 않는것을 알 수 있다. 여기서 말하고자 함은 ‘Product’인터페이스를 구현한 그 어떤 클래스를 객체로 받을 수 있는 것 이다. 이는 자식 클래스들에 대해 밀접하지 않은 관계(의존적이지 않음)가 생긴 것 이다.

create() : 입력받아 showcase에 ‘name’이라는 key로 저장했던 Product의 클론을 만들고 반환한다.

 

MessageBox : 문자열을 테두리로 표시하는 클래스

MessageBox는 입력받은 문자열 s를 장식하여 감싸고 출력하는 클래스 이다. 예를 들어 Hello라는 문자열을 입력하고 dechChar 를 ‘*’로 한다면 출력은 다음과 같이 나온다.

 createClone() : 자기 자신을 복제하여 반환하는 메소드. 호출하고 있는 clone()은 자기 자신(인스턴스)의 복제한 새로운 인스턴스를 만드는 메소드 이다. clone()메소드를 통해서 복제 가능한 것은 java.lang.Cloneable 인터페이스를 구현한 클래스만 가능 하다. 만약 이 인터페이스를 구현하지 않은 클래스를 clone시도 하게 될 경우 ‘CloneNotSupportException’이라는 예외가 발생하게 된다. 그래서 try-catch문을 이용하여 예외 핸들링을 하고 있음을 확인 할 수 있다.

여기에서 사용된 Product 인터페이스는 Cloneable인터페이스를 상속받았기 때문에 위와 같은 예외가 발생하지는 않는다.

 

UnderlinePen : 문자열에 밑줄을 표시하는 클래스

MessageBox와 거의 비슷한 기능을 하지만 다른 출력이 나온다.

 

main클래스에서는 Manager의 인스턴스를 만들고 UnderlinePen과 MessageBox의 인스턴스에 이름을 붙여서 등록하고 사용하는것을 확인할 수 있다.

 

3. 정리 해 봅시다

Prototype에 대한 정리를 하다가 이런 고민이 생겼다. 그냥 ‘new’키워드를 이용해서 인스턴스를 생성하면 될 것이지 왜 복잡한 clone()을 사용하여 인스턴스를 복제 해서 사용하는 것 일까? 위에서 언급했었던 3개의 예시를 들어 정리를 해보면 다음과 같다.

  • 종류가 너무 많아 클래스로 정리 되지 않음. 
    •  예제 프로그램에서는 3개의 ‘prototype’이 등장한다. ‘~’, ‘*’, ‘/’의 글자들을 이용해서 문자열에 어떠한 장식을 표현하는 것 이다. 겨우 3개지만 얼마든지 더 늘어 날 수 있음을 알 수 있다. 그러나 이러한 것들을 일일히 클래스로 만들게 되면 소스 양이나 클래스가 늘어나 하나처럼 관리하기 힘들다는 단점이 있다.
  • 클래스로부터 인스턴스 생성이 어려운 경우. 
    • 이번예제에서는 제대로 알기 힘들 것 이다.
  • framework와 생성할 인스턴스를 분리하려고 하는 경우.
    • 예제에서는 인스턴스의 복사(clone)를 실행하는 부분을 framework패키지 안에  설정한다. 클래스들을 구분하기 위해 클래스의 이름 이 아닌 어떠한 문자열들, 예를 들어 “strong message”나, “slash box”라는 문자열을 이용하여 관리를 한다. 이렇게 되면 만들어져 정해져 있는 클래스의 이름들로부터 벗어나 자유로운 인스턴스 관리를 할 수 있는 장점이 있다.
    • 이는 개발자 입장에서 인스턴스 관리가 더 편해진 것 이라고 할 수 있다.

소스 내부에서 클래스 이름을 사용해서 new하는것은 기본적인 방법이다. 하지만 여기에서 원하고자 하는 주 목적은 소스의 ‘재사용'(모듈화) 이다.  소스내부에서 이용할 인스턴스에 클래스의 이름이 지정되있다면 그 클래스와 분리해서 사용 할 수 없게 된다. 그 클래스에 따라갈 수 밖에 없는 의존적이라고 할 수 있는 것이다.

하지만, 어떠한 문자열을 이용하여 복제된 인스턴스를 관리하게 되면 그러한 클래스의 이름들로부터 벗어나게 된다. key값으로 주어진 어떠한 값(예제에서는 문자열, 그 외 어떠한 값들..)을 이용하여 관리를 함으로서 클래스 이름에 긴밀하게 결합되는 형태가 아닌 부품으로서 독립되어 관리 할 수 있게 되는 것이다.

 

 

 

 

You may also like

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.