객체지향 특강 - 디자인 패턴
- 개발을 할수록 코드가 쌓인다.
- 작성한 코드는 레거시 코드라고 하며, 이를 개선하는 리팩토링 작업을 반복하게된다.
- 개선을 반복하면서 일정한 패턴이 만들어지며, 이를 디자인 패턴이라고 한다.
Unity 에서 자연스럽게 사용하는 디자인패턴들
- Prototype 패턴
- 프립팹을 만들어 사용하는것 자체가 Prototype 패턴에 속함
- Composite 패턴
- 오브젝트에 컴포넌트를 붙여서 사용하는 방식
- Flyweight 패턴
- ScriptableObject 사용이 이 패턴에 속함
그 외 패턴들
Facade 패턴
- Facade : 건물의 정면, 은행의 입구등을 생각하면 된다
- 클래스에 큰 기능들을 묶어둔 뒤, 이에대한 접근 지점을 제공하는 패턴
이 플레이어 클래스가 플레이어의 기능을 묶어두고, 접근지점을 제공하는 파사드 패턴의 예시
public class Player : MonoBehaviour
{
public PlayerController controller;
public PlayerCondition condition;
public ItemData itemData;
public Action addItem;
private void Awake()
{
CharacterManager.Instance.Player = this;
controller = GetComponent<PlayerController>();
condition = GetComponent<PlayerCondition>();
}
}
플레이어의 상태를 당담하는 PlayerCondition 과, 플레이어의 움직임을 당담하는 PlayerContoller 에 접근지점을 제공
클래스 자체는 싱글톤 패턴인 CharacterManager를 통해 접근 가능하도록 되어있음
Bridge 패턴
- 클래스를 따로 만든 뒤, 연결하여 사용
- 인터페이스를 통해 스크립트를 조합하여 사용 가능
- ※ 전략패턴과 유사함
NewShape 에서 인터페이스인 IColorable 을 변수로 가지고, 이를 Getcomponent로 가져옴
public interface IColorable
{
public void PrintColor();
public string ColorString();
public void Movement();
}
public class NewShape : MonoBehaviour
{
protected string s_name;
protected IColorable colorable;
private void Awake()
{
colorable = GetComponent<IColorable>();
Paint();
}
protected virtual void Paint()
{
colorable.PrintColor();
}
}
IColorable을 상속중인 TBlue, 인터페이스 내용인 색 내용을 string으로 반환, 속한 오브젝트의 색을 변경, 움직임을 구현
public class TBlue : MonoBehaviour, IColorable
{
public string ColorString()
{
return "[B]";
}
private void Update()
{
Movement();
}
public void Movement()
{
transform.position += Vector3.down * Time.deltaTime;
}
public void PrintColor()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}
NewShape를 상속받는중인 TCircle, 시작하면서 자신의 이름을 변경
public class TCircle : NewShape
{
private void Start()
{
s_name = "Stone";
gameObject.name = $"{colorable.ColorString()} {s_name}";
}
}
오브젝트에 NewShape 가 존재하면, 여기에 필수로 IColorable 인터페이스를 상속받는 스크립트가 필요함
IColorable를 상속받는 스크립트는 오브젝트의 시작시 오브젝트의 색을 바꾸는 역할을 수행함
브릿지패턴을 사용하지 않을경우, 아래와 같은 방식으로 구현됨
public enum EColor
{
Red,
Blue
}
public enum EShape
{
Circle,
Square
}
public class Shape : MonoBehaviour
{
public EColor color;
public EShape shape;
private string name;
private MeshRenderer meshR;
private void Awake()
{
meshR = GetComponent<MeshRenderer>();
}
void Start()
{
switch (color)
{
case EColor.Red:
meshR.material.color = Color.red;
name += "[R]";
break;
case EColor.Blue:
meshR.material.color = Color.blue;
name += "[B]";
break;
}
switch (shape)
{
case EShape.Square:
name += " SpongeBob";
break;
case EShape.Circle:
name += " Stone";
break;
}
gameObject.name = this.name;
}
}
모양, 색상의 종류가 늘때마다 각 enum 의 길이와, switch 문의 case 가 늘어나게됨
→ 해당 스크립트를 수정하게되면서, 충돌의 가능성이 높아짐
Template Method 패턴
- 부모를 추상클래스로 제작하고, 실제 구현을 자식 클래스에 넘겨줌
- ※ 마찬가지로 전략패턴과 유사함
상호작용 하는 아이템의 클래스
부모는 에임을 대었을때 SetInfo() 메서드를 통해아이템의 정보를 표기하는 기능,
상호작용시 작동할 ItemEffect() 를 호출하는 역할만을 함
그리고 추상 메서드로 SetInfo(), ItemEffect() 를 구현하도록 강제함
public abstract class ItemObject : MonoBehaviour, IInteractable
{
public string itemName;
public float value;
public string GetInteractPrompt()
{
return $"{itemName}\n{SetInfo()}";
}
public void OnInteract()
{
ItemEffect();
}
protected abstract string SetInfo();
protected abstract void ItemEffect();
}
ItemObject 를 상속받은 소모성 아이템과 장착 아이템 클래스.
부모의 메서드인 ItemEffect() 와 SetInfo() 의 실제 구현을 각각 당담하게 됨
public class ItemDash : ItemObject
{
protected override void ItemEffect()
{
CharacterManager.Instance.Player.equip.TryEquip(this);
}
protected override string SetInfo()
{
return "[Equipment] Dash";
}
}
public class ItemHealth : ItemObject
{
protected override void ItemEffect()
{
CharacterManager.Instance.Player.condition.AddHealth(value);
Destroy(gameObject);
}
protected override string SetInfo()
{
return $"[Consumable] Health";
}
}
MVC (model - view - controller) 패턴
- 정보를 스크립터블 오브젝트에 저장
- UI등, 필요한 위치에서 해당 오브젝트의 데이터를 불러와서 사용
- 정보를 저장하는 스크립터블 오브젝트를 생성
- 레벨 정보를 스크립터블 오브젝트에 저장
- 스크립터블 오브젝트에서 레벨값이 오르면 이벤트 작동
- 작동된 이벤트를 바탕으로 UI의 레벨정보값 변경
public class ExampleUI : MonoBehaviour
{
public Text text;
public ExampleData data;
private void Start()
{
data.onChangeLevel += UpdateLevelUI;
}
public void UpdateLevelUI(int level)
{
text.text = $"Level : {level}";
}
}
public class PlayerLevel : MonoBehaviour
{
float time = 0f;
public ExampleData data;
void Update()
{
time += Time.deltaTime;
data.Level = (int)time / 2;
}
}
[CreateAssetMenu(fileName = "ExampleData", menuName = "Data/ExampleData")]
public class ExampleData : ScriptableObject
{
private int level;
public Action<int> onChangeLevel;
public int Level
{
set
{
this.level = value;
onChangeLevel?.Invoke(level);
}
}
}
※ 스크립터블 오브젝트를 사용하는것이 다른 오브젝트를 직접 참조하는것보다 연산이 적음
전략패턴의 사용 기준
- 예시를 들면
- if/ elseif 줄이기
- switch 줄이기
- 불필요한 생성 줄이기
- 생성패턴
- 불필요한 탐색/ 정렬 줄이기
- 구조 패턴
- 불필요한 연산/ 조건문을 줄이기
- 행위 패턴
객체지향의 핵심은 의존성, 결합도를 줄이는것
단, 전략패턴이 이에 반드시 부합하는것은 아님(싱글톤 패턴은 단일책임 원칙에 위배됨, 의존성이 높아짐)
전략패턴을 통해 코드 내부적으로 불필요한 생성, 탐색, 정렬, 연산, 조건문을 줄이기
UGS (Unity Gaming Services)
- 유니티에서 제공하던 서비스들이 파편화 되어있던것을 모으고, 강화해서 나온 서비스
https://cloud.unity.com/home/products
- Cloud Code
- 중요 코드를 기기 외부에서 처리
- 게임 내부적으로, 데이터가 조작되면 밸런스에 문제가 생기는등의 코드를 서버에서 처리함
- Cloud Content Delivery
- 추가 데이터 다운로드 기능
- 스토어등에 표기되는 용량이 과도하게 클 경우 다운로드가 꺼려질 가능성이 있음
- Cloud Save
- 클라우드에 플레이어의 데이터를 저장
- 저장정책
- 모든 행동 저장 : 빅 브라더 모델
- 중요이벤트/ 변경지점/ 심심할때(같은 행동이 반복될때) 저장 : 중도 모델
- 저장을 희망할때만 저장 : 콘솔모델
- 직렬화 하여 저장
- Remote Config
- 게임 외부에서 게임의 프로퍼티 제어
- 패치 없이 특정한 값을 변경할 수 있음
- 광고 노출의 빈도를 바꿔가며, 유저 이탈이 적으면서 수익이 가장 높은 점을 찾는 작업등에 사용
- User Generated Content
- 유저 콘텐츠를 관리 (모드)
UGS 를 사용하는 이유
- AWS (아마존 웹 서비스)
- 구현이 복잡함, 서버 디도스 공격으로인한 요금 문제가 발생할 수 있음
- 파이어베이스
- 모바일 위주의 구현
- 스팀 API
- 오직 스팀만가능, 기능에 제약이 많음
- 뒤끝
- 높은 가격 (단, 모든 문서가 한글로 되어있음 → 접근성이 높음)
- UGS
- 플랫폼을 가리지 않음, 유니티 최적화
인증 서비스
- UGS 에서 무제한 무료로 서비스 제공중
- 익명(게스트), 일반, 소셜 로그인(구글 플레이, 페이스북, 애플 등) 지원
- ※ 제공되는 코드는 일반/구글 플레이 로그인만 제공됨 (구글 플레이 서비스는 별도 패키지를 통해 제공)
- 계정을 생성하면 각 플랫폼별로 계정을 통해 로그인 가능
UGS 사용 주의사항
- 패키지 매니저를 통해 추가 패키지를 받아야 서비스 사용이 가능함
- Cloud Save, Cloud Code, Remove Config 등을 나눠진 패키지를 각각 받아서 사용해야함
- 접속 실패에 관한 내용을 준비해주어야함
- try, catch 문을 사용하여 접속 실패시를 대비해야함
※ async : 비동기 처리,클래스에 사용함으로써 클래스에 속한 메서드에 await를 사용할 수 있음
await 사용시 다른 쓰레드는 내용을 처리하면서 이 메서드는 처리가 완료될때까지 대기하게됨
'내일배움캠프 > TIL' 카테고리의 다른 글
개인프로젝트 - 맵 생성중 발생한 오류 (0) | 2024.11.12 |
---|---|
특강 정리 - 직렬화 2차특강 (1) | 2024.11.11 |
숙련주차 개인프로젝트 - 버그 수정 (0) | 2024.11.07 |
유니티 팀프로젝트 숙련주차 - 발표 시연영상 (0) | 2024.11.06 |
유니티 숙련주차 팀프로젝트 - 병합 완료 (0) | 2024.11.05 |