Java언어로 배우는 디자인패턴 입문 정리 - 6. Prototype Pattern

양정훈·2021년 2월 20일
0
post-thumbnail

본 내용은 Java언어로 배우는 디자인패턴 입문(한빛미디어) 책을 보면서 정리한 내용입니다.

소개

다음과 같은 경우에 인스턴스를 복사(복제)해서 새로운 인스턴스를 만드는 패턴

  • 종류가 너무 많아 한개의 클래스로 할 수 없는 경우
    - 취급하는 객체의 종류가 너무 많아서 하나씩 다른 클래스로 만들면 다수의 소스파일을 작성해야 하는 경우
  • 클래스로부터 인스턴스를 생성하기 어려운 경우
    - 생성하려는 인스턴스가 복잡하는 과정을 거쳐 만들어지기 때문에 클래스로부터 만드는 것이 어려운 경우
    • 그래픽에디터에서 사용자의 마우스 조작에 의해 만들어진 인스턴스를 프로그래밍으로 작성하는 것이 어려움. 사용자의 조작으로 만들어진 인스턴스를 다시 만들고 싶을 때에는 지금 만든 인스턴스를 일단 보존해 두었다가 필요한 경우에 그것을 복사함.
  • 프레임워크와 생성할 인스턴스를 분리하고 싶은 경우
    - 인스턴스를 생성할 때의 프레임워크를 특정 클래스에 의존하지 않도록 만들고 싶은 경우.
    • 이럴 때는 클래스 이름을 지정해서 인스턴스를 만드는 것이 아니라 미리 '모형'이 되는 인스턴스를 등록해 놓고, 등록된 인스턴스를 복사해서 인스턴스를 생성함.

Java 언어에서는 복제를 하는 조작을 'clone'이라고 부르고 있음.

실습예제

UML 다이어그램

정리

  • Prototype(원형)의 역할
    - Prototype 역할은 인스턴스를 복사(복제)해서 새로운 인스턴스를 만들기 위한 메소드를 결정함.
  • ConcretePrototype(구체적인 원형)의 역할
    - ConcretePrototype 역할은 인스턴스를 복사해서 새로운 인스턴스를 만드는 메소드를 실제로 구현함.
  • Client(이용자)의 역할
    - Client 역할은 인스턴스를 복사하는 메소드를 이용해서 새로운 인스턴스를 만듦.

활용법

  • 클래스에서 인스턴스를 만들면 안되는 것
    - 종류가 너무 많아 한개의 클래스로 할 수 없는 경우
    • 클래스로부터 인스턴스를 생성하기 어려운 경우
    • 프레임워크와 생성할 인스턴스를 분리하고 싶은 경우

관련된 다른 패턴

  • Flyweight Pattern
    - Prototype Pattern은 현재의 인스턴스와 같은 상태의 다른 인스턴스를 만들어 이용함.
    • Flywewight Patttern에서는 하나의 인스턴스를 여러 장소에서 공유하여 이용함.
  • Memento Pattern
    - Prototype Pattern에서는 현재의 인스턴스와 같은 상태의 다른 인스턴스를 만들지만 Memento Pattern에서는 스냅샷과 undo를 실행하기 위해 현재의 인스턴스의 상태를 보존함.
  • Composite Pattern & Decorator Pattern
    - Composite Pattern이나 Decorator Pattern을 많이 이용하면 복잡한 구조의 인스턴스가 동적으로 만들어지는 경우가 있음. 이런 경우에는 Prototype Pattern을 사용하면 편리한 점이 있음.
  • Command Pattern
    - Command Pattern에 등장하는 명령을 복제하려고 할 때 Prototype Pattern이 사용되는 경우가 있음.

참고

clone 메소드와 java.lang.Clonable 인터페이스

자바 언어의 clone

자바에서는 인스턴스를 복사하는 기구로서 clone 메소드가 준비되어 있음.
clone 메소드를 실행하는 경우 복사 대상이 되는 클래스는 java.lang.Cloneable 인터페이스를 반드시 구현하고 있어야 함.

복사 대상이 되는 클래스가 직접 java.lang.Cloneable 인터페이스를 구현해도 상관없고 상위 클래스의 어딘가에서 Cloneable 인터페이스를 구현해도 상관없음.
또한 Cloneable 인터페이스의 하위 인터페이스를 구현해도 상관없음.

예제 프로그램에서는 MessageBox 클래스나 UnderlinePen 클래스는 Product 인터페이스를 구현했고, Product 인터페이스는 Cloneable 인터페이스의 하위 인터페이스로 되어 있음.

Cloneable 인터페이스를 구현한 클래스의 인스턴스는 clone 메소드를 호출하면 복사됨.
그리고 clone 메소드의 반환 값은 복사에 의해 만들어진 인스턴스가 됨.
(이때 내부에서는 복사 대상이 되는 인스턴스와 같은 크기의 메모리를 확보해서 인스턴스의 필드 내용을 복사함)

만약 Cloneable 인터페이스를 구현하지 않은 클래스의 인스턴스가 clone 메소드를 불러내면 예외 CloneNotSupportedException(clone이 지원되지 않는 예외)이 발생함.

정리하면 다음과 같음.

  • Cloneable 인터페이스를 구현하고 있는 클래스의 인스턴스 : 복사됨.
  • Cloneable 인터페이스를 구현하고 있지 않은 클래스의 인스턴스 : CloneNotSupportedException을 발생함.

또한 java.lang 패키지는 암암리에 import되고 있기 때문에 소스 내에는 java.lang.Cloneable이라고 쓰지 않고 단순히 Cloneable이라고 쓸 수 있음.

clone 메소드는 어디에서 정의되어 있는가?

clone 메소드는 java.lang.Object 클래스에서 정의되어 있음. Object 클래스는 자바의 클래스 계층에서 최상위 클래스이기 때문에 모든 클래스에서 clone 메소드를 상속하고 있음.

Cloneable이 요구하는 메소드는?

'Cloneable 인터페이스'라고 하면 그 안에 clone 메소드가 선언되어 있는 것처럼 생각하는 경향이 있음.
하지만 그런건 없음. Cloneable 인터페이스에는 메소드가 하나도 선언되어 있지 않음.
인터페이스는 단순히 'clone에 의해 복사할 수 있다'는 상징으로 사용되고 있음.

clone 메소드는 피상적인 복사를 함

clone 메소드는 필드의 내용을 그대로 복사함. 바꿔 말하면 필드의 앞쪽에 있는 인스턴스의 내용까지는 고려하지 않음. clone 메소드를 사용해서 복사를 했을 경우 배열에 대한 참조만 복사될 뿐이고 배열의 요소 하나 하나는 복사되지 않음. 이와 같은 필드 대 필드의 복사를 '피상적인 복사'라고 함. clone 메소드가 수행하는 것은 바로 '피상적인 복사'임

clone이 행하는 '피상적인 복사'만으로 곤란한 경우에는 클래스 설계자가 clone 메소드를 오버라이드해서 자신에게 필요한 '복사'를 정의하는 것도 가능함. (clone 메소드를 오버라이드하는 경우에는 super.clone()을 사용해서 상위 클래스의 clone 메소드를 호출해야 함).

clone은 복사만 할 뿐이고 생성자를 호출하지는 않는다는 점이 주의.
또한 인스턴스 생성시 특수한 초기화를 필요로 하는 클래스에서는 clone 메소드 내에 처리를 기술해야 함.

profile
꿈을 현실로 만드는 성장형 인간

0개의 댓글