목차
개인 과제, 챌린지반 특강 Delegate
오늘은 개인과제 필수 과제들을 완성하고 도전과제 몇개를 추가로 구현할 예정이다.
챌린지반 특강으로 Delegate를 다룬다!
Delegate는 자주 활용하질 않아서, 알지만 잘 안쓰게 되는데 이번 기회로 익숙하게 활용할 수 있게 되면 좋겠다.
챌린지반 특강: Delegate
delegate 반환형 델리게이트이름(매개변수);
delegate void SpawnDelegateFunc();
기본적으로 함수와 구성이 유사하지만 키워드만 앞에 delegate를 붙인다.
사용을 위해서는 델리게이트를 선언해야한다.
delegate void SpawnDelegateFunc(); //1. 델리게이트 선언
void Start()
{
SpawnDelegateFunc spwanAction; //2변수 만들기
spawnAction = SpawnPlayer_ARoom; //4. 델리게이트 변수에 함수 저장. //변수에 저장만 하는 중이고, 실행하는 것이 아니니 괄호()는 붙이지 않는다.
spawnAction(); //5. 델리게이트 실행. //함수를 실행하는 부분이니 괄호()를 붙여서 사용.
}
void SpawnPlayer_ARoom(){...} //3. 사용할 함수 만들기
void SpawnPlayer_BRoom(){...}
void SpawnPlayer_BossRoom(){...}
void SpawnPlayer_RandomPlace{){...}
이 기능을 왜 쓰는 걸까요?
개발에서 이렇게 번거로운 짓을 하게 된다면 대부분 한가지이다. -> 확장성
이외데오 모듈화, 재사용, 디커플링 등이 있지만 오늘은 확장성에 주목.
팝업창에 대해서 생각해보자. (확인, 취소 버튼)
게임 종료 메시지 뿐만 아니라, 캐릭터 바꾸기, 강화 확인, 친구 추가 등등 여러 상황에 팝업 메시지를 띄운다.
동일한 상황인데 서로 다른 기능이다.
팝업 기능마다 함수를 만들어두거나 팝업별로 클래스를 따로 만드는 것은 비효율적이다.
이럴때 delegate를 사용한다.
함수의 매개변수로 변수를 넘기듯이 델리게이트를 넘길 수 있다.
이런식으로 필요한 기능을 별도로 구현해두지 않고 전달받은 기능만 실행하도록 하면 여러 상황에 대응할 수 있게 된다.
delegate
함수에 대한 참조 타입이다. 함수를 변수처럼 저장하거나 매개 변수로 전달할 수 있다.
event
기본적으로 delegate의 한 종류. (조금 더 정확히는 델리게이트를 클래스/구조체 멤버에 표현하는 문법: 외부에서 +- 할 수 있게)
옵저버 패턴과 유사하게 활용할 수 있게 도와준다.
event 델리게이트 이름 변수이름;
다른 객체에 함수를 전달 -> 저장 -> 실행
배틀 중 패배했을 때 처리해야할 작업들이 많아진다.
인풋 기능 중지, 패배 UI 띄우기 등등
이는 UI, Manager, Controller 등에서 관리하게 된다.
구현 방법은 크게 2가지가 있다.
1. 캐릭터가 UI, Controller, Manager 등을 찾아서 Die에서 호출하는 방법.
이 경우 해당 클래스들을 미리 접근해서 가지고 있어야 한다.
기능이 많아질수록 다시 추가해 나가야한다.
2. 반대로 UI, Controller, Manager가 계속해서 플레이어를 체크하다가 체력이 0이 되면 실행하는 방법.
계속해서 체크해야하기 때문에 성능에 무리가 갈 수 있다.
여기서 적용 가능한 것이 옵저버 패턴
구독을 한 애들한테만 소식을 전한다.
event는 이 구독 기반의 로직에 주로 이용된다.
1. event를 등록해두면
2. 필요한 함수들을 여기에 등록
3. event 발생 시 등록된 기능들을 전부 실행
Start()에서 이벤트에 += 하는 부분이 있다. 이 부분에서 event에 함수를 등록하게 된다.
이런식으로 event는 키보드를 눌렀을 때, 플레이어가 패배 했을 때, HP가 변경 되었을 때 등 특정 상황을 체크하고 있다가 행동하는 방법에 주로 사용한다.
Delegate vs Event
delegate
함수를 저장해서 실행하는 게 본래 의미.
어떤 요청을 했을 때 그 결과를 처리하는 것을 만들 수 있다. (콜백)
외부에서 실행 가능.
(1:1 관계에 유용, 전달 받은 메서드 실행, 비동기 처리 - 데이터 로드, 네트워크, 사용자 인터렉션 완료 - 팝업 결과)
event
이벤트를 예약해두고 필요할 때 해당 기능들을 실행.
외부에서 실행 불가.
(1:N 관계에 유용)
Action
Action은 C#에서 제공하는 편의성 향상 버전 delegate 타입이다.
Action을 사용하지 않으면 매번 delegate를 만들어서 사용해야한다.
이럴 경우 이벤트가 추가될 때마다 delegate를 추가해서 만들어야 한다.
public event Action<Vector2> onMoveEvent;
매개변수로 넘기는 부분은 Action 뒤에 제네릭으로 추가한다.
매개변수가 하나가 아니라면 최대 16개까지 콤마 , 로 구분하여 추가할 수 있다.
.이렇게 Action을 활용하면 delegate를 만들지 않고 편하게 활용할 수 있다.
편의성 향상 버전 표준 delegate 타입
Action 💡 💡 💡
반환값이 없는 델리게이트 타입 (완료 팝업, 통신 결과 출력 등)
알림이나 콜백 처리에 편리하다.
Func 💡 💡 💡
반환값이 있는 델리게이트 타입 (유사 팩토리)
public delegate TResykt Func<out TResult>(); //리턴값 하나 필수. (마지막에 위치)
매개변수 16개까지 추가 가능. (result 제외)
리턴값을 여러개 가지고 싶으면? -> 클래스/구조체, 튜플 활용
LINQ는 기본적으로 Func로 구성되어 있음 (Func<T, bool>) -> LINQ 쿼리 짤 때 활용 가능.
Predicate 💡
반환값이 bool인 델리게이트 타입 (특정한 데이터 필터링)
잘 안쓰는 이유
- 코드가 오히려 번거로워지는 경우가 많음.
- 범용성이 떨어짐.
Func<T, bool>이 같은 기능이면서 훨씬 활용도가 좋음. (LINQ 포함)
가장 합리적인 사용처는 List, Array의 필터 기능
Find, FindAll, Exists, FindLast, FindIndex등이 Predicate으로 구현됨.
EventHandler
이벤트를 다룰 때 표준으로 쓰이는 델리게이트 타입 -> C# 표준이긴 함.
우리는 event를 쓸 것.
event + Action 이 꿀 조합.
event + Func은 가능은 하나 기본적으로 의도가 다르므로 권장하지는 않음. // event-> 1:N 알림 // Func-> 1:1 요청/응답
알아두면 좋은 점.
event 사용 후에 구독 해지는 필수!
해지하지 않으면 사용하는 것으로 판단하며 GC 처리가 되지 않아 메모리 누수가 됨.
등록은 OnEnable (+=)
해지는 OnDisablt (-=) <-세트
Unity 라이프 사이클 상 가장 안전
- 활성화된 오브젝트만 등록
- 파괴되거나 씬 넘어가기 전에 안전하게 이벤트 해제
Q. 다른 델리게이트도 똑같이 메모리 누수 방지를 고려해야 하나요? A. 델리게이트는 신경써주어야한다. 이벤트가 아니면 보통 일회성으로 사용되기는 한다.
람다보다는 만들어진 메서드를 등록하는 게 좋다. -> 등록/해지에 같은 인스턴스를 연결해야 한다.
delegate와 패턴
기능상으로는 유사한 형태
행동을 분리(캡슐화)하는 패턴과 비슷함
Action Command
Func Strategy, Factory
Predicate Specification
event Observer
애초에 디자인 패턴이 처음 나왔을 때 delegate 같은 함수 포인터가 불완전했음.
인터페이스 + 구현 방법이 패턴이 되었음.
지금은 언어의 발전으로 상당 부분의 패턴들을 대체할 수 있다.
| delegate | 디자인 패턴 | |
| 구조의 규모 | 메서드 레벨의 기능 | 시스템 / 모듈 / 구조 레벨 |
| 구조의 안전성 의도 파악 |
가독성을 좋으나 의도를 명확하게 파악하기는 제한 됨. 델리게이트마다 목적이 달라질 수 있다. |
설계를 통해 목적을 구분할 수 있다. 일관된 구조. |
| 구현 난이도 | 간단하게 구현 | 구조적인 설계가 필요 |
| 활용 케이스 | 작고 단순한 기능 (생산성 UP) 일회성 기능 작은 규모의 범위에 적합 Unity 이벤트, 콜백 처리 |
시스템 전반에 걸친 활용 여러 객체의 협력이 필요한 경우 기능의 일관성을 유지해야 할 때 |
패턴을 만들고 내부 구현을 delegate로 하는 것도 좋은 방법이다.
예. Factory 패턴의 내부 구현체를 Func로
무명 메서드
단순한 기능, 1번 쓰고 말 기능은 delegate를 사용하기 번거롭다.
함수를 클래스에 따로 만들어두지 않고 1회용 함수를 만들어서 활용
private Action<string> printName;
printName = delegate(string s)
{
printName?.Invoke
};
람다
더 단축해서 delegate 키워드, 매개변수 타입도 생략 가능
private Action<string> printName;
printName = (s) => {
printName?.Invoke(s);
};
느낀점
잠이 부족하다.. 집중이 되지 않아서 멍때리기를 반복했던 것 같다.
예전부터 생각한건데 폐 끼치기 싫다는 강박 덕분에 팀작업을 할때 효율이 나오는 것 같다.
팬데믹 때 우울증이 심각했을 때도 개인과제랑 시험은 안했으면서 팀과제는 혼자 캐리해서 A~A+ 받았을 정도니까. (기말 제출 안해서 F 받았다.)
이 성향을 어떻게 개인 공부 시에도 끌어올릴 수 있을지, 아니면 최대한 팀으로 작업하는 것을 지향하여 유지하는 게 나을 지 고민을 해봐야할 것 같다.
내일 학습 할 것은 무엇인지
오늘 마무리하지 못한 플랫폼 움직이기를 마무리해야한다.
그리고 어제 생각했었던 장비를 진행하고, 레이저 트랩, 플랫폼 발사기를 구현하면 얼추 도전과제 80%는 완료할 수 있을 것 같다.
'부트캠프 > 본캠프' 카테고리의 다른 글
| [내일배움캠프_2025AUG18] 팀 프로젝트 3일차: 장착관리 (0) | 2025.08.19 |
|---|---|
| [내일배움캠프_2025AUG13] 개인 과제 제출, 단기 프로젝트 (0) | 2025.08.13 |
| [내일배움캠프_2025AUG11] 개인 과제 시작 (0) | 2025.08.11 |
| [내일배움캠프_2025AUG08] 유니티 숙련 챕터 마무리 (0) | 2025.08.08 |
| [내일배움캠프_2025AUG07] 유니티 숙련 챕터 (0) | 2025.08.07 |