📌 01. 인터페이스와 열거형
🔹 다중 상속을 사용하지 않는 이유
- 다이아몬드 문제(Diamond Problem): 동일한 멤버를 두 부모 클래스로부터 상속받을 경우 충돌 발생 가능.
- 설계 복잡성 증가: 클래스 관계가 복잡해지고 유지보수가 어려워짐.
- 이름 충돌 가능성: 동일한 이름의 멤버 충돌 처리 필요.
- C#의 단일 상속 원칙: 깔끔한 구조 유지를 위해 인터페이스로 대체.
🔹 인터페이스 사용 이유
- 재사용성: 다양한 클래스가 같은 동작 구현 가능.
- 다중 상속 가능: 클래스는 단일 상속이지만 인터페이스는 다중 구현 가능.
- 유연한 설계: 느슨한 결합 구조 가능.
🔹 인터페이스란?
- 인터페이스는 메서드, 속성 등의 **형식(시그니처)**만을 정의하는 일종의 설계도다.
- **구현(내용)**은 포함하지 않으며, 이 인터페이스를 사용하는 클래스가 해당 멤버들을 직접 구현해야 한다.
- 마치 "이런 기능이 있어야 해!"라고 규칙을 강제하는 느낌.
// 인터페이스 정의
interface IMyInterface
{
void Method1();
int Method2(string str);
}
// 인터페이스를 구현한 클래스
class MyClass : IMyInterface
{
public void Method1() { }
public int Method2(string str) => 0;
}
인터페이스를 통해 클래스가 특정 기능을 반드시 구현하도록 강제할 수 있다.
🔹 게임 응용 예시
- 이동 인터페이스
public interface IMovable { void Move(int x, int y); }
public class Player : IMovable
{
public void Move(int x, int y)
{
Console.WriteLine($"플레이어가 ({x}, {y})로 이동합니다");
}
}
다양한 게임 객체가 동일한 방식으로 '이동'이라는 기능을 구현하도록 할 수 있다.
- 아이템 인터페이스 예시
public interface IUsable { void Use(); }
public class Item : IUsable
{
public string Name { get; set; }
public void Use() => Console.WriteLine($"{Name}을 사용했습니다");
}
소비 가능한 아이템이라면 IUsable을 통해 일관된 사용 로직을 제공할 수 있다.
- 다중 인터페이스 구현 예시
public interface IItemPickable { void PickUp(); }
public interface IDroppable { void Drop(); }
public class Item : IItemPickable, IDroppable
{
public string Name { get; set; }
public void PickUp() => Console.WriteLine($"{Name}을 주웠습니다");
public void Drop() => Console.WriteLine($"{Name}을 버렸습니다");
}
하나의 클래스에서 다양한 인터페이스를 통해 여러 기능을 동시에 지원 가능.
🔹 인터페이스 vs 추상 클래스
구분 인터페이스 추상 클래스
| 상속 | 다중 구현 가능 | 단일 상속만 가능 |
| 멤버 구현 | 구현 없음 | 구현 포함 가능 |
| 사용 | 동작 정의 | 공통 기능 공유 |
인터페이스는 규약(약속), 추상 클래스는 기반 기능 제공의 느낌.
📌 02. 열거형 (Enum)
🔹 개념 설명
- 열거형은 관련된 상수들의 집합이다.
- 정수에 이름을 부여한 것으로, 코드 가독성과 유지보수에 큰 도움을 준다.
- 내부적으로는 정수형이며, 기본값은 0부터 시작한다.
🔹 예시
// 요일 열거형 정의
enum DaysOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
DaysOfWeek today = DaysOfWeek.Monday;
Console.WriteLine("오늘은 " + today); // 출력: 오늘은 Monday
// 게임 아이템 희귀도 열거형
enum ItemRarity { Common, Uncommon, Rare, Epic }
숫자 대신 의미 있는 이름을 부여하여 가독성과 유지보수를 향상시킨다.
📌 03. 예외 처리 및 값/참조형
🔹 예외 처리 개념
- **예외(Exception)**란 실행 도중 발생하는 오류 상황이다.
- 예외 처리는 프로그램의 비정상 종료를 방지하고, 오류를 우아하게 처리하게 해준다.
try
{
int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
Console.WriteLine("0으로 나눌 수 없습니다.");
}
finally
{
Console.WriteLine("항상 실행됨");
}
try: 예외 가능성 있는 코드, catch: 오류 발생 시 처리, finally: 무조건 실행되는 블록.
🔹 사용자 정의 예외
public class MyException : Exception
{
public MyException(string msg) : base(msg) { }
}
예외 클래스를 직접 정의하면 상황별로 더 구체적인 오류 대응이 가능하다.
🔹 값형 vs 참조형
- 값형(Value Type): 값을 직접 저장. 복사되므로 독립적.
- 참조형(Reference Type): 주소(참조)를 저장. 같은 데이터 공유함.
int a = 5;
int b = a;
b = 10; // a는 여전히 5
MyClass obj1 = new MyClass();
MyClass obj2 = obj1;
obj2.Value = 100; // obj1.Value도 100으로 바뀜
🔹 박싱(Boxing) & 언박싱(Unboxing)
- 박싱: 값형 → 참조형으로 변환 (힙에 저장)
- 언박싱: 참조형(object) → 값형으로 꺼내는 작업
int x = 10;
object obj = x; // 박싱
int y = (int)obj; // 언박싱
많이 쓰이진 않지만, 컬렉션(List) 등에서 타입이 섞일 때 활용된다.
📌 04. 델리게이트, 람다, LINQ
🔹 델리게이트 개념
- 메서드를 변수처럼 다루게 해주는 타입이다.
- 함수 포인터 느낌. 콜백 구조 만들기 좋음.
delegate int Calculator(int x, int y);
Calculator calc = (a, b) => a + b;
Console.WriteLine(calc(3, 5)); // 출력: 8
🔹 람다식 (Lambda)
- 메서드 이름 없이 쓰는 간단한 익명 함수.
Action<string> print = msg => Console.WriteLine(msg);
print("안녕하세요!");
이벤트 등록, LINQ 처리 등에 주로 쓰인다.
🔹 Func & Action
Func<int, int, int> adder = (a, b) => a + b;
Action<string> printer = s => Console.WriteLine(s);
Func은 반환형 있음 / Action은 반환형 없음
🔹 LINQ 기본 예제
- LINQ는 컬렉션 데이터를 SQL처럼 쿼리할 수 있게 해주는 문법이다.
List<int> nums = new List<int>{ 1, 2, 3, 4, 5 };
var evenNums = from n in nums where n % 2 == 0 select n;
foreach (var n in evenNums)
Console.WriteLine(n); // 2, 4
📌 05. 고급 자료형 - Nullable, StringBuilder
🔹 Nullable 형식
- 원래 값형(int, float 등)은 null을 가질 수 없다.
- int?처럼 ?를 붙이면 null 허용이 된다.
int? score = null;
int finalScore = score ?? 0; // null이면 0으로 대체
?? 연산자는 null 대체 값 제공 (null-coalescing operator)
🔹 StringBuilder
- 문자열을 반복해서 연결하거나 조작할 때는 +보다 효율적.
- 내부적으로 가변 버퍼를 이용해서 문자열을 구성한다.
StringBuilder sb = new StringBuilder();
sb.Append("Hello").Append(" World");
string msg = sb.ToString();
Console.WriteLine(msg);
문자열 조작이 많은 경우 꼭 써야 하는 도구.
🎯 유니티가, 아니 다 떠나서 게임엔진이라는게 괜히 GOAT 가 아니구나... 거긴 컴포넌트만 끼우면 알아서 다 해줬는데, 지금은 진짜 내가 머리로 구조를 다 짜야 하니까.
그래도 이제는 코드가 조금씩 읽히고, "아 이건 이 기능이구나" 싶은 것도 느껴지긴 해. 근데 막상 백지에서 똑같이 직접 쓰라고 하면 진짜 아무 생각도 안 나서 멍해진다. 그래서 더더욱 이번 정리가 중요하다고 느낌. 적어도 이 문서 계속 반복해서 보면서 복습하면 개념이 선명해질 거라는 희망은 있음.
다음 주 시험 준비하면서 이 문서를 몇 번씩 읽고, 손으로 예제도 타이핑하면서 익숙해지려고 한다. 지금은 감으로 뭔가를 따라치는 느낌이 강한데, 결국은 내가 설계부터 직접 할 수 있어야 하잖아. 아직은 어렵지만, 계속 반복하면 언젠가는 진짜 내 머리에서 기능이 그려지고 손이 먼저 나가겠지.
그래도 지금은 적어도 코드가 "읽히는" 상태인 게 다행이라고 생각한다. 처음엔 뭔 말인지도 몰랐는데, 이제는 "아 이런 뜻이구나"는 알겠거든. 다음엔 내가 실제로 "게임에 어떻게 쓰일지"까지 자연스럽게 떠올릴 수 있었으면 좋겠다. 아직 갈 길은 멀지만, 유니티 없이도 조금씩 적응해 가는 중이라는 데 의의를 둔다.
'팀스파르타 코딩' 카테고리의 다른 글
| 📚 TIL - 2025년 4월 18일 (금) / Unity Text RPG 구현 리뷰 (0) | 2025.04.18 |
|---|---|
| 📚 TIL - 2025년 4월 17일 (목) / 알고리즘 기초 정리 (0) | 2025.04.17 |
| 📚 복습 정리 - 텍스트 RPG 개발에 사용된 C# 개념들 (개념 + 실습 응용) (0) | 2025.04.16 |
| 스파르타 던전 프로젝트 기능 설명 및 트러블 슈팅 (0) | 2025.04.16 |
| 📘내일의 학습 목표: 인터페이스와 열거형 (1) | 2025.04.15 |