Skip to content

Prototype #12

@simoniful

Description

@simoniful

Prototype 패턴의 정의는 코드를 클래스에 종속시키지 않고 기존에 존재하던 객체를 복사할 수 있는 디자인 패턴입니다.

  • 복사 방법을 선언하는 prototype 프로토콜입니다.
  • prototype 프로토콜을 준수하는 prototype class입니다.

어떤 객체가 존재하고 해당 객체와 정확하게 똑같은 객체를 만들고 싶을 때 Prototype 패턴을 사용할 수 있습니다. 어떻게 하면 특정 객체와 동일한 객체를 만들 수 있을까요? 일단 클래스와 같은 참조 타입을 복사하는 방법에는 얕은 복사(shallow copy)와 깊은 복사 (deep copy)가 있습니다. 얕은 복사는 그냥 새로운 변수에 기존 객체를 할당하는 방법인데, 이렇게 생성한 객체는 기존 객체를 계속 가리키고 있기 때문에 새로운 객체를 만든 것이라 할 수 없습니다. 따라서 해당 객체의 모든 정보를 동일하게 가진 새로운 객체를 만들기 위해서는 깊은 복사를 해줘야 하며 Prototype 패턴은 이러한 작업을 쉽게 할 수 있도록 도와주는 패턴입니다.

사용

이 패턴을 사용하여 객체 자체를 복사할 수 있습니다. 예를 들어, Foundation은 NSCopying 프로토콜을 정의합니다. 그러나 이 프로토콜은 Objective-C용으로 설계되었으며 안타깝게도 Swift에서는 잘 작동하지 않습니다. 여전히 그것을 사용할 수 있지만, 결국 직접 더 많은 보일러 플레이트 코드를 쓰게 됩니다. 따라서 Swift에서 사용가능한 직접 깊은 복사가 가능한 프로토콜을 구현합니다.

이를 해결하는 가장 간단한 방법은 원본 객체의 모든 값을 가지고 직접 새로운 객체를 만드는 방법입니다. 이렇게 직접 만드는 경우 접근 제한자가 private인 프로퍼티에는 접근할 수 없기 때문에 복사를 하지 못할 수도 있습니다. 또한 복사본을 만들기 위해 원본 객체의 클래스를 알아야 하기 때문에 코드가 해당 클래스에 종속되어 의존성이 발생합니다. 

따라서 Prototype 패턴을 활용하여 매번 객체를 직접 만들기보다는, 기존 객체의 정보와 동일한 정보를 갖는 새로운 객체를 생성하는 역할을 하는 프로토타입 클래스를 만들어서 간편하게 사용할 수 있습니다. 또한 프로토타입이 인터페이스를 갖는 객체를 허용하여 클래스 의존성도 해결할 수 있습니다. 즉 객체의 복제를 직접 하는 것이 아닌 프로토타입 클래스에 넘겨서 처리하는 패턴이라고 할 수 있습니다.

주의 사항

기본적으로 슈퍼클래스 인스턴스를 서브클래스의 복사 이니셜라이저에 전달할 수 있습니다. 서브클래스가 슈퍼클래스 인스턴스에서 완전히 초기화될 수 있다면 이것은 문제가 되지 않을 수 있습니다. 그러나 하위 클래스가 새 속성을 추가하는 경우 상위 클래스 인스턴스에서 이를 초기화하지 못할 수 있습니다. 이 문제를 완화하기 위해 서브클래스 복사 이니셜라이저를 "사용할 수 없음"으로 표시할 수 있습니다. 이에 대한 응답으로 컴파일러는 이 메서드에 대한 직접 호출을 컴파일하는 것을 거부합니다.

copy() 메서드를 통해 간접적으로 호출하는 것은 여전히 ​​가능합니다. 그러나 이러한 안전장치는 대부분의 useCase에 충분히 효과적입니다. 하지만, 이렇게 해도 사용 사례에 대한 문제가 방지되지 않으면 정확히 어떻게 처리할지 고려해야 합니다. 예를 들어 콘솔에 오류 메시지를 인쇄하여 충돌하거나 대신 기본값을 제공하여 처리할 수 있습니다.

정리

  • Prototype 패턴을 사용하면 객체 자체를 복사할 수 있습니다. 복사 방법을 선언하는 prototype 프로토콜과 해당 인터페이스를 준수하는 class의 두 가지 유형이 포함됩니다.
  • Foundation은 NSCopying을 제공하지만 Swift에서는 잘 작동하지 않습니다. 자신만의 prototype 프로토콜을 쉽게 구성할 수 있으므로 Foundation이나 다른 프레임워크에 전적으로 의존할 필요가 없습니다.
  • prototype 프로토콜을 만드는 핵심은 init(_ prototype:) 형식으로 복사되는 이니셜라이저를 만드는 겁니다.
  • 프로토타입을 사용하면 클라이언트에 프로토타입 인스턴스를 등록하기만 하면 새로운 객체를 복제할 수 있게 됩니다. 이를 런타임에서 처리하기 때문에 다른 생성 패턴보다 유연하다고 할 수 있습니다.
  • 새로운 객체를 만들 때 default 값이 아닌 다른 값으로 객체를 생성할 수 있게 됩니다.
  • 다양한 구조로 객체를 하위 클래스에서 만들 수 있게 됩니다.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions