Chapter 7. 원형 패턴(Prototype Pattern)

Date:     Updated:

카테고리:

태그:

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

Chapter 7. Prototype Pattern

🔔 Prototype Pattern

image

오브젝트를 새로 생성할시 기존 오브젝트의 복사본으로 생성하여 내용만 조금 수정해준다.

  • Prototype을 상속 받아 clone() 메소드를 구현하는 ConcretePrototype으로 구성되어 있다.
  • 원형을 하나 가지고 있고, 원형의 Prototype을 상속 받아 clone() 메소드를 구현한 상태라면 Client 에서 원할 때 원형으로 클론을 만들어 사용할 수 있다.

사용하는 이유

  • 인스턴스 만들 때 newInstantiate을 사용하면 그만인데 왜 프로토타입 패턴을 사용할까?
    • 프로토타입 패턴은 비슷한 오브젝트를 지속적으로 생성해야 할 때 유용하게 사용할 수 있다.

      • 아예 새로운 오브젝트를 지속적으로 생성 new 하는건 부담스러운 일이기 때문.
      • 그보다 싼 비용인 본래의 오브젝트의 복사본을 만들어 내어 (서로 다른 인스턴스), 각 객체에 따라 데이터 수정을 해주는 방식으로 오브젝트를 생성한다.
  • 동적 클래스 확장
    • 약간의 설정 변경으로 비슷하지만 다른 클래스로의 확장이 가능한 경우, 세부 클래스를 미리 명세하지 않고
    • 런타임 때 원형을 복제해서 그 복사본을 수정함으로써 동적으로 오브젝트를 생성함.


🔔 예제 1

구조

  • 📜IUnit.cs
    • 🧾Iunit 인터페이스
      • Clone() 함수
        • 모든 유닛들은 Clone()함수를 가진다.
    • 🧾Marine
      • 👉🏻 🧾Iunit 인터페이스 상속
        • Clone() 함수 오버라이딩
    • 🧾Firebat
      • 👉🏻 🧾Iunit 인터페이스 상속
        • Clone() 함수 오버라이딩
  • 📜UnitManager.cs
    • 원형 패턴 사용!
      • 설명은 밑에서 확인

📜Unit.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 'IPrototype' interface
public interface IUnit
{
    // Method for cloning
    IUnit Clone();
}

// 'ConcretePrototype1' class implements IPrototype interface
public class Marine : IUnit
{
    public int Hp { get; set; }
    public int AttackPower { get; set; }

    // Implement shallow cloning method
    public IUnit Clone()
    {
        // Shallow Copy
        return this.MemberwiseClone() as IUnit;

        // Deep Copy
        // Implement Memberwise clone method for every reference type object 
        // return ..
    }
}

public class Firebat : IUnit
{
    public int Age { get; set; }
    public int AttackPower { get; set; }

    // Implement shallow cloning method
    public IUnit Clone()
    {
        // Shallow Copy 
        return this.MemberwiseClone() as IUnit;
    }
}

MemberwiseClone() 함수 in C#

해당 객체를 얕은 복사단순 복사본 객체를 생성하고 리턴한다.

  • 객체 복사를 위해 C# Object 클래스에서 지원하는 함수
    this.MemberwiseClone() as IUnit;
    
    • IUnit 타입으로 this(Firebat, Marine 객체)의 사본을 생성한다.
  • 깊은 복사를 하려면 이 함수 말고 따로 개발자가 직접 깊은 복사 내용을 구현해야 한다.


📜UnitManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UnitManager : MonoBehaviour {

	void Start () {
        Marine marine = new Marine();
        marine.Hp = 25;
        marine.AttackPower = 5;

        // clone Marine object with Clone method
        // If you will not set the new value for any field the it will take the default value
        // from original object
        Marine marineClone = (Marine)marine.Clone();
        marineClone.Hp = 30;  // 값만 수정해준다.
        marineClone.AttackPower = 6;  // 값만 수정해준다.

        Debug.Log("Marine Details");
        Debug.LogFormat("Age: {0} / AttackPower: {1}",marine.Hp, marine.AttackPower);

        Debug.Log("Cloned Marine Details");
        Debug.LogFormat("Age: {0} / AttackPower: {1}", marineClone.Hp, marineClone.AttackPower);

        // you can perform the same operation for Firebat
    }
}
  • 마린 최초의 생성은 new를 사용하여 생성한다.
  • 두번째 마린부터는 새로 생성하지 않고 기존 마린으로부터 복사본을 만든 후 내용만 수정해준다.
  • 원본인 marine과 복사본인 marineClone은 별개의 객체이다.


🔔 예제 2

  • 유니티에서 🟦프리팹은 이미 프로토 타입을 따르고 있었다.
    • 원형인 🟦프리팹을 복사해서 ⬜오브젝트로 찍어내는 것이기 때문.
    • 프리팹이 Instantiate되어 생성된 오브젝트들은 모두 프리팹의 복사본이다.
    • 여기서 내용만 조금 수정될 뿐.

📜Marine.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Marine : MonoBehaviour
{
    void Start()
    {
        float r = Random.Range(0.0f, 1.0f);
        float g = Random.Range(0.0f, 1.0f);
        float b = Random.Range(0.0f, 1.0f);

        Renderer rend = GetComponent<Renderer>();
        rend.material.color = new Color(r, g, b, 0f);   
    }

    void OnCollisionEnter(Collision collision)
    {
        Debug.Log("OnCollisionEnter");
        Destroy(this.gameObject);
    }
}
  • 게임이 시작되면 위 📜Marine.cs 스크립트가 붙는 오브젝트의 색상이 랜덤하게 설정된다.
  • 📜Marine.cs 스크립트가 붙는 오브젝트가 어떤 물체와 충돌하면 오브젝트를 파괴한다.


📜UnitManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UnitManager : MonoBehaviour {

    public GameObject unit;
    public Transform tr;

	void Start () {
    }

    public void CreateUnit()
    {
        GameObject obj = Instantiate(unit);
        obj.transform.position = tr.position;
    }
}
  • unit에 프리팹을 드래그 앤 드롭하여 연결한다.
  • unit 프리팹을 복사하여 obj 오브젝트를 만들어낸다.
  • CreateUnit() 이 함수는 버튼 이벤트로 연결할 것.


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Design Pattern 카테고리 내 다른 글 보러가기

댓글 남기기