프로토타입(Prototype) 패턴

2024. 10. 14. 05:35Design Pattern

Prototype 패턴

Prototype 패턴생성 패턴(Creational Pattern) 중 하나로, 객체를 직접 생성하는 대신 이미 존재하는 객체를 복제하여 새로운 객체를 만드는 방법을 제공합니다.
이 패턴은 성능이 중요한 경우나 객체를 반복적으로 생성할 때 사용할 수 있습니다.


1. Prototype 패턴이란?

Prototype 패턴은 객체를 생성하는 데 필요한 복잡한 과정을 피하기 위해 기존 객체의 복제본을 만드는 방식입니다.
이를 통해 객체를 생성하는 데 필요한 시간을 절약할 수 있으며, 새로운 인스턴스를 만드는 대신 기존 객체를 복사하는 방식을 채택하여 유연성을 제공합니다.

언제 사용하는가?

  • 객체 생성 비용이 클 때: 복잡한 초기 설정이나 많은 자원을 사용하는 객체의 경우, 복제하여 새로운 객체를 생성하는 것이 더 효율적입니다.
  • 객체의 초기 설정이 반복될 때: 객체의 구성이 복잡하거나 반복적으로 생성해야 하는 경우 Prototype 패턴이 유용합니다.

2. Prototype 패턴의 구조

Prototype 패턴의 구조는 크게 Prototype 인터페이스ConcretePrototype 클래스로 나뉩니다.

Prototype 인터페이스

  • Clone 메서드: 복제 기능을 정의하는 인터페이스로, 이 메서드를 통해 객체의 복제가 이루어집니다.

ConcretePrototype 클래스

  • Clone 메서드 구현: Prototype 인터페이스를 구현한 실제 클래스입니다. 이 클래스는 복제 가능한 구체적인 객체로, 객체의 복제를 책임집니다.

3. Prototype 패턴의 구현 예시 (C#)

// Prototype 인터페이스
public abstract class Shape
{
    public string Id { get; set; }
    public abstract Shape Clone();
}

// ConcretePrototype 클래스
public class Circle : Shape
{
    public int Radius { get; set; }

    // Clone 메서드를 오버라이드하여 객체를 복제
    public override Shape Clone()
    {
        return (Shape)this.MemberwiseClone(); // 얕은 복사
    }

    public override string ToString()
    {
        return $"Circle: Radius = {Radius}, Id = {Id}";
    }
}

public class Rectangle : Shape
{
    public int Width { get; set; }
    public int Height { get; set; }

    public override Shape Clone()
    {
        return (Shape)this.MemberwiseClone();
    }

    public override string ToString()
    {
        return $"Rectangle: Width = {Width}, Height = {Height}, Id = {Id}";
    }
}

위 코드에서는 Shape 클래스가 Prototype 패턴을 구현하는 추상 클래스이며, Circle과 Rectangle 클래스는 그 구체적인 구현체들입니다. MemberwiseClone() 메서드를 사용하여 객체를 얕게 복사합니다.

클라이언트 코드

public class Program
{
    public static void Main(string[] args)
    {
        Circle circle1 = new Circle { Radius = 10, Id = "1" };
        Circle circle2 = (Circle)circle1.Clone(); // Circle 객체 복제
        circle2.Id = "2";
        circle2.Radius = 20;

        Console.WriteLine(circle1); // Circle: Radius = 10, Id = 1
        Console.WriteLine(circle2); // Circle: Radius = 20, Id = 2

        Rectangle rect1 = new Rectangle { Width = 5, Height = 10, Id = "3" };
        Rectangle rect2 = (Rectangle)rect1.Clone();
        rect2.Id = "4";
        rect2.Width = 15;

        Console.WriteLine(rect1); // Rectangle: Width = 5, Height = 10, Id = 3
        Console.WriteLine(rect2); // Rectangle: Width = 15, Height = 10, Id = 4
    }
}

위 예시에서는 Circle과 Rectangle 객체를 각각 복제하여 새 객체를 만들고, 새롭게 복제된 객체의 속성을 변경해도 원본 객체에는 영향을 미치지 않음을 보여줍니다.


4. 깊은 복사 vs 얕은 복사

Prototype 패턴에서 복제 방식은 크게 깊은 복사(Deep Copy)얕은 복사(Shallow Copy)로 나뉩니다.

  • 얕은 복사(Shallow Copy): 객체의 참조만 복사하는 방식으로, 원본 객체와 복제된 객체가 같은 참조 객체를 공유합니다. MemberwiseClone()이 얕은 복사를 수행합니다.
  • 깊은 복사(Deep Copy): 객체의 참조뿐 아니라 그 내부에 있는 모든 객체까지 새롭게 복사하는 방식입니다. 깊은 복사는 일반적으로 더 복잡하며, 모든 하위 객체까지 복제해야 합니다.

5. Prototype 패턴의 장단점

장점:

  • 복잡한 객체 생성 비용 절감: 객체를 처음부터 생성하는 비용을 줄이고, 객체를 빠르게 복제할 수 있습니다.
  • 유연성: 객체의 복제본을 쉽게 만들 수 있어 코드 재사용성이 높아지고, 다양한 형태의 객체를 빠르게 생성할 수 있습니다.

단점:

  • 깊은 복사 구현의 복잡성: 깊은 복사를 구현하려면 객체의 모든 필드와 하위 객체를 수동으로 복제해야 하므로 코드가 복잡해질 수 있습니다.
  • 복제 과정에서 오류 발생 가능성: 객체가 복잡해질수록 복제 과정에서의 오류 가능성이 커질 수 있습니다. 특히 복제된 객체가 원본 객체와 예상치 못한 참조를 공유하는 경우 문제가 발생할 수 있습니다.

6. Prototype 패턴의 사용 사례

6.1. 게임 개발

게임 개발에서는 다양한 캐릭터, 무기, 아이템을 효율적으로 생성하기 위해 Prototype 패턴이 자주 사용됩니다.
기본 템플릿을 복제하여 새로운 아이템이나 캐릭터를 빠르게 만들 수 있습니다.

6.2. 문서 편집기

문서 편집기에서 여러 종류의 서식이 적용된 문서를 빠르게 생성할 때, Prototype 패턴을 사용하여 기본 서식을 복제하여 새로운 문서를 생성할 수 있습니다.


Prototype 패턴은 객체를 새로 생성하는 대신 복제하여 필요한 객체를 효율적으로 생성할 수 있는 패턴입니다.
성능과 메모리 관리 측면에서 유리하며, 객체를 복잡하게 생성하는 대신 복제하여 빠르게 사용할 수 있습니다. 깊은 복사와 얕은 복사에 대한 이해를 바탕으로 적절한 상황에서 이 패턴을 적용하면 성능 향상과 코드 유연성을 얻을 수 있습니다.