오르카의 아틀리에

UniRx에서는 여러가지 애플리케이션 패턴 중에서도 MV(R)P 패턴을 권장한다. 다른 서드파티 라이브러리를 통하여 MVVM을 활용하는 방법도 있는 것같지만 일단 공식 Github Readme에서 추천하는 패턴은 MV(R)P이다. 안드로이드나 WPF 개발에 대해서 다루어보았다면 MVP패턴과 다른 패턴들에 대해서 들어보았을 것이다. 기본적인 지식은 Realm의 기술 블로그에서 알아 볼 수 있다.

MV(R)P?!

위 그림은 공식 Github Readme에 사용된 그림이다. 게임을 UI를 통해 유저와 게임을 이어주고 게임에 관련된 정보들(점수, 적, 아이템 등)을 컨트롤하는 과정이라고 생각하면 View를 통해 Input을 받고, Model 값을 표시해 줄 수 있다. 그 중간에서 Presenter는 View와 Model을 구독하고 적절한 로직을 처리하여 View와 Model을 업데이트하는 역할을 한다.


음... 그럼 Presenter는 View는 uGUI와 Object들에 대한 이벤트를 구독해서 처리한다고 치고, Model과는 어떻게 상호작용을 할 수 있을까? UniRx는 이 부분을 원활하게 처리하기 위해 ReactiveProperty라는 것을 제공한다.


ReactiveProperty?!

직역해서 보면 '반응하는 프로퍼티(속성)'정도일까? 말 그대로 ReactiveProperty는 값이 변화할 때마다 스트림에 메시지를 전달하게 된다. 같은 종류의 Model들을 모아두는 클래스를 하나 만들고 해당 객체에 접근하여 ReactiveProperty에 접근하여 구독하게 되면 그 값이 변할 때마다 알 수 있게 되는 것이다.


정리해보면 View는 일어나는 이벤트에 대해서 구독하고 Model은 값의 변화를 감지하는 구독을 하게 되는 것이다. 보통 View에서 이벤트를 감지하고 적절한 로직을 수행한 뒤 Model을 업데이트해야 한다면 업데이트하고, Model은 변화가 일어났으니 Model 구독 로직에서 View를 업데이트하는 행동을 취해주면 하나의 사이클이 완성된다. 간단한 예제 코드를 보도록 하자.



간단하게 축약한 예제이기 때문에 조금만 읽어보면 어떻게 동작하는지 보일 거라고 생각한다. Click Event전달과 Model 변경 알림 부분을 분리시켜 좀 더 느슨하게 연결하였고, Text에 바인드는 자주 사용하는 패턴이기 때문에 별도의 오퍼레이터로 빼둔 것을 알 수 있다. 


활용은 어떻게?!

예제와 같이 활용하면 된다. Generic을 지원하지만, 대부분의 Game data는 string, float, int일 것이니 기본 타입들만 사용해서도 충분히 Model을 제작 가능하다.  저장해야하는 Model들이 많아지면 가독성이 떨어지거나 대량의 비슷한 ReactiveProperty들을 반복 구독해야 하는 일이 생기지 않을까? 라고 생각할 수도 있겠지만, UniRx는 Collection, Dictionary타입도 ReactiveDictionary<T>, ReactiveCollection<T> 같은 형태로 제공하고 있기 때문에 적절하게 사용한다면, 코드를 간결하게 만들 수있다.


또한, 보통의 경우에는 Presenter가 View는 SerializeField를 이용하여 '참조'하게되고, Model의 같은 경우는 Model을 관리하는 Singleton 패턴의 ModelManager를 사용하거나, 직접 Presenter 내부에 생성하여 가지고 있는 형태를 하는 것이 일반적이다. (개인적으로 여러 Presenter와 공유하는 Model이 있을 수 있으니 ModelManager를 활용하는 편이 좋을 것으로 생각한다.)


특히, 게임에 따라 Model의 크기가 클 수도 있고, 저장 기능은 거의 필수적이기 때문에 Model을 저장해두었다가 불러올 수 있는 작업을 해야 한다. ReactiveDictionary<T>를 XML로 전환하여 저장하는 메소드를 만들어 두면, 자동 저장이나 명시적인 저장을 구현할 때 편리할 것이고 저장된 자료를 Load하는 메소드를 만들어 두면, 생성자에서 그 메소드를 활용하여 불러오기 기능을 구현할 수도 있다. 저장을 지원하지 않는 게임이 아닌 이상 이런 메소드들을 구상하고 구현하는 것이 좋고 어떤 구조로 저장할 것인지 생각하여 메소드들을 만들어두면 나중에 필요할 때마다 사용할 수 있을 것이다.