공부일지

싱글톤의 변형과 제네릭 개념 본문

코딩/Unity

싱글톤의 변형과 제네릭 개념

이하택 2023. 9. 27. 22:53

추가 조사 없이 TIL 적으려 내 맘대로 비유하고 정의 내린 부분이 많음.

오브젝트란 무엇인가?

  • 우리가 변수 선언하고 카메라 설정하는 모든 것들은 전부 오브젝트를 만드는 과정이다.


큐 설명

  • 선입선출


사용하는 입장에서의 제네릭

예제 1 : 랜덤으로 큐브 만들기

  • 우리는 C#에서 프로그램이 main()에서 시작함을 알고 있다.
  • 사운드매니저, 게임매니저 등등 스크립트가 많아지면 어디서 시작하는지를 알기 어려움.
  • 이와 비슷하게 메인이 되는 진입점인 GameScene을 만들어 진행함.

  • GameScene.cs
    public class GameScene : MonoBehaviour
    {
    	void Start()
    	{
    		Debug.Log(CharacterManager.Instance);
    	}
    }

  • CharacterManager.cs - 싱글턴 MK.2
    • 기존 방식
      public class CharacterManager : MonoBehaviour
      {
      	public static CharacterManager instance;
      	private void Awake()
      	{
      		instance = this;
      	}
      }

    짬 좀 찼으니까 오브젝트가 꺼져있다면 인스턴스가 만들어지지 않으므로 구조를 변형해야함.

    public class CharacterManager : MonoBehaviour
    {
    	private stiatc CharacterManager _instance; //싱글턴, 아직 null, 실체
    	public static CharacterManager Instance; //프로퍼티, 위의 것을 감싸는 껍데기
    	{
    		get
    		{
    			if(_instance == null)
    			{
    				//다른 오브젝트는 new로 선언할 수 없지만, ~~~여기부터 질문하기.
    				GameObject go = new GameObject("CharacterManager");
    				_instance = go.AddComponenet<CharacterManager>();
    
    				DonDestroyOnLoad(_instance);
    			}
    			return _instance;
    		}
    	}
    
    	private const int EnemyCount = 10;
    	private const string EnemyPrefName = "Enemey";
    
    	private void Start()
    	{
    		for(int i = 0; i < _enemyCount; i++)
    		{
    			GameObject res = Resources.Load<GameObject>("Enemy");
    
    			float randX = Random.Range(-10, 10);
    			float randX = Random.Range(-10, 10);
    
    			GameObject instantiate = Instantiate(res, new Vector3(randX, y:0, randZ), Quaternion.identity)
    		}
    	}
    }

  • GameManager.cs
    public class GameManager : MonoBehaviour
    {
    	private stiatc CharacterManager _instance; //싱글턴, 아직 null, 실체
    	public static CharacterManager Instance; //프로퍼티, 위의 것을 감싸는 껍데기
    	{
    		get
    		{
    			if(_instance == null)
    			{
    				//다른 오브젝트는 new로 선언할 수 없지만, ~~~여기부터 질문하기.
    				GameObject go = new GameObject("CharacterManager");
    				_instance = go.AddComponenet<CharacterManager>();
    
    				DonDestroyOnLoad(_instance);
    			}
    			return _instance;
    		}
    	}
    
    	Queue respawnQueue = new Queue; //리스폰대기열
    
    	private float curTiem = 0f;
    	private float resapwnTime = 2f;
    
    	private void Update()
    	{
    		if(Input.GetMouseButtonDown(0))
    		{
    			//지금 로직에 상관없는 부분. 그러려니 하셈
    			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    			RacastHit hit;
    
    			if(Physics.Raycast(ray, out hit))
    			{
    				Debug.Log(hit.collider.name);
    
    				//2번 변형
    				//
    			}
    		}
    		public void RegisterRespawn(GameObject go)
    		{
    			respawnQueue.Enqueue(go);
    		}
    	}


당장은 개념을 배우는 과정이니 게임 로직은 무시하고

  • 그럼 차라리 게임 오브젝트만 집어넣어 보시라!

  • 어차피 형식이 지정되어 있으니, 꺼낸 놈은 게임오브젝트로 사용하면 되기에 중간과정 생략.
  • 예외 처리 안 함.
  • 타입 확인 안 함.


만드는 입장에서의 제네릭

예 1)

  • 중복되는 부분 추출해서 함수로 뽑아내버리겠다!!!!

예 2) 싱글턴

생각해보자

  • 상속?
  • 문제점
    • 이때 사용하는게 제네릭 = 일반화

    • 이럴 때에 제네릭에 제약을 걸어주면 좋아죽음
  • 따라서 어차피 게임오브젝트 올거니까 게임 오브젝트 대상인 함수를 가져다 쓰겠다.

따라서 아래와 같이 제네릭에 클래스명을 기입하여 싱글톤 처리가 완료된다.

장점

  • 오류방지
  • 예외처리
  • 가독성
  • 성능향상 (if문으로 경우의 수 따지는게 노이득이라)

var에 넣을 때와 object에 넣을 때의 차이

  • Object : 들어가는 대상이 실제 오브젝트로 형변환이 일어남.
  • var : 값이 초기화되는 그 순간 해당 값의 타입으로 고정

  • 이렇게 타입 이름 길어서 쓰기 싫을 때 var 선에서 정리

Uploaded by N2T