오늘은 유니티에서 사용하는 클래스의 두 가지 종류와 객체 지향의 캡슐화에 대해 정리해 보겠습니다.
유니티에서는 클래스가 크게 두 가지 형태로 구분되어 사용됩니다.
일반 C# 클래스 (Plain Class)
new 키워드로 직접 인스턴스를 만들 수 있습니다. 데이터나 로직의 묶음을 관리하기에 좋으며, 예를 들어 플레이어의 능력치 데이터를 담는 PlayerStatData 같은 클래스가 이에 해당합니다.
MonoBehaviour (컴포넌트 스크립트)
유니티의 컴포넌트 시스템으로, 절대 new로 생성해서는 안 됩니다. 게임 오브젝트에 AddComponent로 붙이거나 프리팹을 Instantiate로 생성할 때만 사용할 수 있습니다.
public class PlayerHealthData
{
private int _hp;
public int Hp => _hp;
public PlayerHealthData(int hp) { _hp = hp; }
}
// MonoBehaviour 예시: new 사용 불가
public class PlayerHealthComponent : MonoBehaviour
{
[SerializeField] private int hp = 100;
private void Awake() { /* 초기화 로직 */ }
}
클래스 내부의 데이터를 관리할 때는 필드와 프로퍼티라는 두 개념을 명확히 구분해야 합니다.
Field (필드)
필드는 클래스 내부에 선언된 변수로, 데이터를 실제로 저장하는 물리적인 메모리 공간을 의미합니다. 외부에서 함부로 건드리지 못하게 보통 private으로 처리하여 데이터를 보호합니다.
Property (프로퍼티)
프로퍼티는 겉보기에는 변수처럼 보이지만 실제로는 동작(Method)에 더 가깝습니다. 비유하자면 금고 앞에 서 있는 은행원과 같아서, 돈을 꺼내달라(get)거나 넣어달라(set)는 요청을 검증하고 처리합니다.
프로퍼티는 접근자(get)와 변이자(set)를 통해 데이터를 제어합니다.
get: 내부의 데이터를 외부로 꺼내어 보여주는 역할을 합니다. 이 블록 안에서는 데이터를 수정하지 않고 오직 읽기만 수행하는 것이 원칙입니다.
set: 외부에서 들어온 값을 내부 변수에 저장하는 역할을 합니다. 잘못된 데이터가 들어오지 못하게 막는 필터링 기능을 수행할 수 있습니다.
value: set 블록 안에서만 사용할 수 있는 암시적 매개변수입니다. 외부에서 입력한 값을 잠시 담아두는 임시 보관함 역할을 합니다.
private int _hp;
public int Hp
{
get { return _hp; }
set
{
// value를 사용하여 0 미만으로 떨어지지 않게 검증 로직 추가
if (value < 0) _hp = 0;
else _hp = value;
}
}
람다 연산자(=>)는 식 본문(Expression Body)이라고도 불리며, 코드를 극도로 압축해 줍니다. 화살표가 가리키는 곳이 결과값임을 직관적으로 보여주어 읽기 전용 프로퍼티를 만들 때 매우 유용합니다.
// 정석 표현
public int Id { get { return _id; } }
// 람다를 사용한 축약 표현
public int Id => _id;
데이터를 복잡한 과정을 거쳐 관리하는 이 과정은 객체 지향의 핵심 원칙인 캡슐화라고 불립니다. 데이터를 껍질 안에 숨기고 안전한 통로(get, set)만 제공함으로써, 프로그램이 예상치 못한 값 때문에 망가지는 것을 원천 봉쇄하기 위함입니다.
오늘은 유니티의 클래스 구분법과 데이터를 안전하게 보호하는 캡슐화에 대해 배웠습니다.
예전에는 public, private가 주는 의미에 대해 깊게 생각해보지 않았는데 데이터 변조의 문제에 대해 이해할 수 있었고 그렇기 때문에 프로퍼티를 통한 데이터 송수신의 중요성에 대해서도 이해할 수 있었습니다.
또 람다 연산자를 통한 코드 압축도 새롭게 알게 되었는데 앞으로 코드 작성에 있어 유용하게 쓰일 수 있을 것 같습니다.