본문 바로가기
Study/디자인 패턴

[C#/Unity][디자인패턴] 프로토타입 패턴(Prototype Pattern)

by 스테디코디스트 2023. 11. 17.
반응형

1. 프로토타입 패턴이란?

- 어떤 객체에 대한 프로토타입을 만들어 놓고 그것을 복사해서 사용하는 패턴

- Clone을 이용하여 객체를 생성하는 방법

- 본래의 오브젝트의 복사본을 만들어 각 객체에 따라 데이터를 수정해주는 방식으로 오브젝트를 생성

- 기존에 생성된 객체를 이용하여 해당 타입의 객체를 생성

- 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정, 인스턴스는 새 객체를 만들기 위해 자기 자신을 복제

- 유니티에서는 Instantiate()가 같은 역할을 하도록 구현되어 있음.

- 객체들을 그의 특정 클래스들에 결합하지 않고 복제할 수 있도록 하는 생성 디자인 패턴

 

2. 프로토타입 패턴을 사용하는 경우

- 비슷한 오브젝트를 지속적으로 생성해야 할 경우

- 클래스로부터 인스턴스 생성이 어려운 경우

- Framework와 생성하는 인스턴스를 분리하고 싶은 경우

- 종류가 너무 많아서 클래스로 정리할 수 없는 경우

 

3. 프로토타입 패턴의 장점

1) 추상화 : 객체를 만드는 복잡한 과정을 숨길 수 있음.

2) 효율성 : 기존 객체를 복제하는 과정이 새 인스턴스를 만드는 것보다 비용면에서 효율적일 수 있음.

3) 유연성 : clone에서 반환하는 타입이 clone을 정의한 클래스와 반드시 동일할 필요는 없다. 즉 클래스의 계층 구조가 있을 때 추상화된 타입을 반환할 수 있는 유연성이 있음.

 

4. 프로토타입 패턴의 단점

1) 구현의 복잡성 : 인스턴스를 복제하는 과정 자체가 복잡할 수 있음.

2) 적용의 어려움 : 복제과정을 통해 객체를 생성하는 것이 어려운 경우 적용하기 어려움

 

5. 코드 구현

- IExercise라는 인터페이스를 통해 얕은 복사 함수들을 정의해주고, 각 클래스마다 이를 재정의하여 사용한다.

- 최초 생성되는 fit라는 객체가 프로토타입의 역할을 하고, 이후 생성되는 shallow와 deep이 프로토타입 fit을 복사해서 사용하는 새로운 객체들이다.

- string과 StringBuilder의 차이를 알고 싶다면 다음을 참고하자.

 

[C#] 문자열 String, StringBuilder 차이점(feat 얕은 복사, 깊은 복사)

✍️먼저 아래의 간단한 C# 코드의 출력을 예상해보자. string s1 = "AA"; string s2 = s1; string s3 = string.Copy(s1); Console.WriteLine(s1); Console.WriteLine(s2); Console.WriteLine(s3); Console.WriteLine("--------------------------------

steadycodist.tistory.com

using System;
using System.Net;
using System.Text;

namespace StudyCSharp
{
    public interface IExercise
    {
        // cf) 복사의 종류
        // 1. 얕은 복사(Shallow Copy) : 주소 값이 같은 인스턴스 생성(한 쪽 수정시 다른 쪽이 영향을 받음)
        // 2. 깊은 복사(Deep Copy) : 주소 값이 다른 인스턴스 생성(원본과 별개)

        // 얕은 복사
        IExercise ShallowCopyClone();
        
        // 깊은 복사
        IExercise DeepCopyClone();
    }

    public class ExerciseID
    {
        public int ID;

        public ExerciseID(int Id)
        {
            this.ID = Id;
        }
    }

    public class Fitness : IExercise
    {
        public string risk { get; set; }            // 위험도(A~F)

        public StringBuilder time { get; set; }     // 평균 운동 시간(0h~10h)

        public int strength { get; set; }           // 강도(0~5)

        public ExerciseID exerciseID { get; set; }  // 넘버링(0~100)
        
        public IExercise ShallowCopyClone()
        {
            // 얕은 복사(Shallow Copy)
            // MemberwiseClone() 함수 : C# 내장함수, 얕은 복사로 객체의 단순 복사본을 생성하고 리턴해줌.
            return (IExercise)MemberwiseClone(); // IExercise 타입으로 this의 복사본을 생성

            // ** 주의 ** 
            // string은 참조타입이지만 불변성을 가지므로 새로운 객체를 생성하게 되어 얕은 복사가 일어나지 않음.
            // int 또한 불변성을 가지기 때문에 새로운 객체를 생성해서 재할당하는 과정이 일어나기 때문에 얕은 복사가 일어나지 않음.
            // StringBuilder와 ExerciseID 클래스는 각각 string과 int를 얕은 복사로 어떻게 이용하는지 보여준다.
        }

        public IExercise DeepCopyClone()
        {
            Fitness clone = new Fitness(); // 새로운 객체 생성

            clone.risk = risk;
            clone.time = new StringBuilder().Append(time);
            clone.strength = strength;
            clone.exerciseID = new ExerciseID(exerciseID.ID);
            return clone;
        }
    }

    public class Crossfit : IExercise
    {
        public string risk { get; set; }            // 위험도(A~F)

        public StringBuilder time { get; set; }     // 평균 운동 시간(0h~10h)

        public int strength { get; set; }           // 강도(0~5)

        public ExerciseID exerciseID { get; set; }  // 넘버링(0~100)

        public IExercise ShallowCopyClone()
        {
            return this.MemberwiseClone() as IExercise;
        }

        public IExercise DeepCopyClone()
        {
            // 깊은 복사(Deep Copy)
            Crossfit clone = new Crossfit(); // 새로운 객체 생성

            // 현재 값 복사 -> 새로운 객체에 저장됨.
            clone.risk = risk; /*clone.risk = string.Copy(risk);*/   // 둘 다 똑같이 깊은 복사가 일어남 -> string 불변성
            clone.time = new StringBuilder().Append(time);
            clone.strength = strength; 
            clone.exerciseID = new ExerciseID(exerciseID.ID);
            return clone;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 최초 생성(Prototype)
            Fitness fit = new Fitness();
            fit.risk = "C";
            fit.time = new StringBuilder("1.5h");
            fit.strength = 4;
            fit.exerciseID = new ExerciseID(1);

            // 복사본 생성
            Fitness shallow = (Fitness)fit.ShallowCopyClone();
            Fitness deep = (Fitness)fit.DeepCopyClone();

            Console.WriteLine("[원본]");
            Console.WriteLine("위험도 \t\t: {0}", fit.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", fit.time);
            Console.WriteLine("강도 \t\t: {0}", fit.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", fit.exerciseID.ID);
            Console.WriteLine();

            Console.WriteLine("[얕은 복사]");
            Console.WriteLine("위험도 \t\t: {0}", shallow.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", shallow.time);
            Console.WriteLine("강도 \t\t: {0}", shallow.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", shallow.exerciseID.ID);
            Console.WriteLine();

            Console.WriteLine("[깊은 복사]");
            Console.WriteLine("위험도 \t\t: {0}", deep.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", deep.time);
            Console.WriteLine("강도 \t\t: {0}", deep.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", deep.exerciseID.ID);
            Console.WriteLine();

            Console.WriteLine("-----------------------------------------------");

            // 원본 값 수정
            fit.risk = "Z";
            fit.time.Replace("1.5h", "2h");
            fit.strength = 3;
            fit.exerciseID.ID = 99;

            Console.WriteLine("-----------------------------------------------");

            Console.WriteLine();
            Console.WriteLine("[수정 후 원본]");
            Console.WriteLine("위험도 \t\t: {0}", fit.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", fit.time);
            Console.WriteLine("강도 \t\t: {0}", fit.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", fit.exerciseID.ID);

            Console.WriteLine();
            Console.WriteLine("[수정 후 얕은 복사]");
            Console.WriteLine("위험도 \t\t: {0}", shallow.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", shallow.time);
            Console.WriteLine("강도 \t\t: {0}", shallow.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", shallow.exerciseID.ID);

            Console.WriteLine();
            Console.WriteLine("[수정 후 깊은 복사]");
            Console.WriteLine("위험도 \t\t: {0}", deep.risk);
            Console.WriteLine("평균 운동 시간 \t: {0}", deep.time);
            Console.WriteLine("강도 \t\t: {0}", deep.strength);
            Console.WriteLine("운동 고유 번호 \t: {0}", deep.exerciseID.ID);
            Console.WriteLine();
        }        
    }        
}

 

출력 결과


<참고 사이트>

 

 

Chapter 7. 원형 패턴(Prototype Pattern)

인프런에 있는 이재환님의 강의 게임 디자인 패턴 with Unity 를 듣고 정리한 필기입니다. 😀

ansohxxn.github.io

 

C# - 디자인 패턴 - 프로토 타입 패턴 ( Prototype Pattern)

1. 요약 GoF 중 생성 패턴으로 프로토 타입 패턴은 Clone을 이용하여 객체를 생성하는 방법입니다. 추상 팩토리 패턴의 경우 객체를 생성하는 코드를 파생 클래스에서 작성을 하였다면, 프로토 타

math-development-geometry.tistory.com

 

유니티 프로그래밍 패턴 (4) Prototype

Prototype Pattern 이란? 프로토타입 패턴Prototype Pattern은 생성하는 방법에 대한 패턴입니다. 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며 인스턴스는 새 객체를 만들기 위

dev-mark.tistory.com

 

 

유니티(C#)로 사용해 보는 디자인 패턴_ProtoType Pattern_프로토타입

프로토 타입 이번 예제에서는 몬스터의 리스폰을 프로토 타입으로 구현해 보았습니다. Monster.cs public class KMS_Monster { public int health; public int speed; public int positionX; public int positionY; public virtual KMS_Mo

mrhook.tistory.com

 

 

C#으로 작성된 프로토타입 / 디자인 패턴들

/ 디자인 패턴들 / 프로토타입 / C# C#으로 작성된 프로토타입 프로토타입은 객체들​(복잡한 객체 포함)​을 그의 특정 클래스들에 결합하지 않고 복제할 수 있도록 하는 생성 디자인 패턴입니다

refactoring.guru

 

 

프로토타입 패턴 [Prototype Pattern] : 복사하여 인스턴스 만들기

이번에 다룰 패턴은 Prototype 패턴이다. 이 패턴은 인스턴스를 생성할 때 사용하는 패턴 중 하나인데, 객체를 복사하는 방식으로 인스턴스를 생성해 낸다. 마치 만화 나루토에서 나오는 그림자 분

orcacode.tistory.com

 

 

[객체 생성 패턴] Chapter 5-3. Prototype Pattern : 장단점

✍️ 프로토타입, 정리 프로토타입 패턴을 간단하게 정리하자면, 기존의 인스턴스를 청사진 삼아 새로운 인스턴스를 생성하는 방법으로 Prototype interface는 clone 메서드를 추상화하고, 클래스는

kangworld.tistory.com

 

 

[Design Pattern] 프로토타입 패턴(prototype pattern)

목차프로토타입 패턴이란?복사 연산 이용하기직렬화팩토리 패턴과의 결합정리하며참고자료 1. 프로토타입 패턴이란?객체를 생성할 때 종종 다른 객체의 값을 복사하여 사용할 때가 있다. 특히,

haedallog.tistory.com

 

 

[Dev] 프로토타입 패턴 (prototype)에 대해 알아보자

프로토타입 패턴 (Prototype Pattern) 프로토타입 패턴은 객체 지향 디자인 패턴 중 하나이며, 객체의 생성 과정을 단순화하여 새로운 객체를 생성하는 방법을 제공합니다. 이 패턴은 이미 존재하는

gr-st-dev.tistory.com