접근제한자, Property
- 인스펙터 창
유니티에서, 인스펙터창에 스크립트 내에서 변수를 띄우긴 위해서는 public을 사용하거나, [SerializeField]를 붙여주면 된다. 처음 공부할 때는, 스크립트(클래스)도 여러개가 아니고, 각각 따로따로 작성하다보니 아무생각없이 인스펙터에서 변수들을 띄우기 위해 public을 사용했다. 하지만 public은 단순히 인스펙터창에 변수를 띄우기만을 위해 사용하는 것은 좋지 않은 습관이라 생각한다. (참고로 [HideInspector]를 이용하면, public을 써도 인스펙터에서 보이지 않는다)
-참고 : 직렬화 규칙 (https://docs.unity3d.com/kr/2020.3/Manual/script-Serialization.html)
1. public이거나 SerializeField 속성이 있어야함
2. static이 아니어야 함
3. const가 아니어야 함
4. readonly가 아니어야 함
4. 직렬화할 수 있는 fieldtype이 있어야함
따라서 유니티에서는 [SeriazlieField]를 이용하면, public이 아닌 변수여도 인스펙터창에 띄울 수 있다. (참고로 Dictionary는 외부 asset을 쓰지않는 이상, 직렬화를 지원하지 않는 것으로 안다. Odin Inspector라는 외부 asset을 쓰면 Dictionary또한 직렬화가 가능하다.)
- Public
그러면 인스펙터에 띄울 뿐만아니라, public을 사용하는 이유는 다른 스크립트에서 그 변수를 참조하기 위해서이다.
예를들어 Player 스크립트에서 Enemy 스크립트의 enemyHp 변수를 알고싶을 때, GetComponet나 Player 스크립트가 component로 있는 오브젝트에 Enemy 스크립트가 component로 있는 object를 등록하는 등,
아무튼 Enemy스크립트의 enemyHp를 찾아올 수 있다.
그래서 처음 배울때는 사실 접근제한자의 중요성도 잘 몰랐고, public은 접근도 허용하고 장점만 있는줄 알았다. 하지만
다른 스크립트에서 건드리면 안되는 변수를 건드리는 등, 기억력의 한계로 인해 나도 모르게 내부에서만 사용하는 변수에 접근하는 등, 결국 건드리면 안될 것을 건드릴 수 있다.
그 외에 접근제한자로는
private: 같은 클래스 내에서만 접근 가능
protected: 같은 클래스 및 파생 클래스에서 접근 가능가 있다.
또 internal: 같은 어셈블리(Assembly) 내에서만 접근 가능기능을 하는는 접근제한자가 있다는데, 본인 기준으로는 써본적이없다..굳이?
물론 기억력이 아주 뛰어나다면 상관없겠지만, (게임) 개발이 하루 이틀안에 끝나는 것도 아니고, 늘 혼자하는 것도 아닌지라, 미래와 과거의 나, 또는 다른 팀원들과의 협업을 생각하면 적절한 접근 제한자 사용은 필수라 생각한다.
-Property
그러면 property를 사용하는 이유는 객체지향 프로그래밍 때문이다.
예를들어서, Player가 Item을 산다고 가정해보자. 그러면은 Player는 Item.cs에 접근을 해는데, 이때 Player.cs에서는 Item.cs에 있는 name이라는 string 변수를 얻을 수 있고, name 값 자체를 바꿀 수는 없다.
즉 값을 알기만하고 수정할수는 없는 상태를 원하는 것이다.
그렇기에 프로퍼티를 사용하면, Get은 Public하게, Set은 Private하게 작동할 수 있다.
그러면 위에 상황에서, Item의 Name은 얻을 수 있지만, 변경은 할 수 없다는
또한 단순히 Get, Set만 하는 것이 아니라, 결국 Get, Set 프로퍼티도 Method이며, 코드를 확장시킬 수 있다.
public int numOfProjectiles
{
get
{
return (int)this.StatContainer[StatType.Projectiles].Modify((float)this.weaponData.numOfProjectiles);
}
}
예시로 지금 개발중인 프로젝트의 코드를 긁어왔는데, 결론은 단순히 Set된 Value를 Get하는것이 아니라, Get자체에서 value를 저렇게 return할 수 있다. 예시 코드는 발사체(Projectile)의 수에 대한 Getter인데, Player의 Stat값과 합쳐진 수를 Return한다.
물론 Set도 마찬가지다. 처음배웠을때는 도대체 왜쓰나 싶은 문법이였고, 이해도 안되는데, 요즘 그나마 제대로 이해가된 것 같아서 참 기분이 좋아졌다.
- 사용시 주의할점
1.불필요한 프로퍼티 사용을 지양하기.
프로퍼티는 단순히 변수를 읽고 쓰는 용도로만 사용하는 것이 아니라, 변수에 대한 접근을 제어하는 기능을 가지고 있기 때문에, 프로퍼티를 사용하는 이유가 분명히 있어야한다. 불필요하게 쓰면 가독성이 너무 떨어지긴 한다.
2. 복잡한 로직을 프로퍼티로 사용하지말기.
사실 위에서 이미 복잡해보이는 로직을 쓰긴썼는데, 사실한줄짜리코드이고, 복잡하지는 않다 ㅎㅎ..
물론 프로퍼티의 주 목적은 접근제한자이니 . 복잡한 로직은 메서드에서 처리하는 것이 좋다.
3. 무한 반복 호출 주의
GhatGPT한테서 어쩌다 보니 얻은 정보인데 일단 첨부한다.
public class Player
{
private int _health;
public int Health
{
get { return Health; }
set { Health = value; }
}
}
public class Player
{
private int _health;
public int Health
{
get { return _health; }
set { _health = value; }
}
}
위 코드에서 Health 프로퍼티의 get, set 메서드에서 각각 Health를 호출하고 있어서. 이 경우 Health 프로퍼티를 읽거나 쓸 때 무한 반복 호출이 발생하여 프로그램이 멈출 수 있다. 이러한 오류를 방지하기 위해서는 아래와 같이 수정해야한다.