https://developers.cyberagent.co.jp/blog/archives/4262/
Model과 View를 분리하기 위해 MVP 패턴을 기반으로 함.
MVP의 M은 Model , V는 View , P는 Presenter 를 나타냄.
MVP패턴은 구현방법이 워낙 다양해서 정도는 없다.
Presenter는 Model과 View를 알고있지만
Model과 View는 Presenter를 몰라서 상호참조를 하지 않음.
MVP 패턴의 필수요소
1. Presenter가 Model의 값의 변화를 감지하여 View를 조작 함
2. Presenter가 View의 사용자 입력을 감지하여 Model을 조작함
Presenter는 Model과 View를 알고있기 때문에 직접 조작가능하지만, View와 Model은 모르기 때문에 이벤트 방식으로 구현해야한다.
Model -> Presenter의 값 변경은 UniRX의 ReactiveProperty을 사용하면 쉽게 구현 가능하다.
Model의 구현
IReadOnlyReactiveProperty 인터페이스만을 공개하여 외부에서 값을 직접 변경하는 것을 금지함.
사실 public으로 SetTiming이 공개되어있기때문에 같기는 하다.
public class SettingModel
{
private ReactiveProperty<int> _timing;
public IReadOnlyReactiveProperty<int> Timing
{
get { return _timing; }
}
public SettingModel()
{
_timing = ReactiveProperty<int>(0);
}
public void SetTiming(int timing)
{
_timing.Value = timing;
}
}
View의 구현
View쪽에서는 각 입력에 대한 이벤트 호출로 이루어져있다.
함수 중 OnTimingChanged(int)는 Model 값에 변화을 업데이트함
public class SettingView : MonoBehavior
{
[SerializeField]
private UILabel _timingLabel;
public Action OnPlusButtonClickedListener;
public Action OnMinusButtonClickedListener;
public Action OnAutoButtonClickedListener;
public Action OnResetButtonClickedListener;
public void OnTimingChanged(int timing)
{
_timingLabel.text = timing.ToString();
}
public void OnPlusButtonClicked()
{
OnPlusButtonClickedListener?.Invoke();
}
public void OnMinusButtonClicked()
{
OnMinusButtonClickedListener?.Invoke();
}
public void OnAutoButtonClicked()
{
OnAutoButtonClickedListener?.Invoke();
}
public void OnResetButtonClicked()
{
OnResetButtonClickedListener?.Invoke();
}
}
Presenter의 구현
View는 인스펙터에서 할당하고 Model은 내부에서 생성한다.
(내부로직도 Presenter가 맡는 형태로 구현되었다.)
public class SettingPresenter : MonoBehavior
{
[SerializeField]
private SettingView _view;
private SettingModel _model;
public void Initialize()
{
_model = new SettingModel();
Bind();
SetEvents();
}
private void Bind()
{
_model.Timing
.Subscribe(_view.OnTimingChanged)
.AddTo(gameObject);
}
private void SetEvents()
{
_view.OnPlusButtonClickedListener = OnPlusButtonClicked;
_view.OnMinusButtonClickedListener = OnMinusButtonClicked;
_view.OnAutoButtonClickedListener = OnAutoButtonClicked;
_view.OnResetButtonClickedListener = OnResetButtonClicked;
}
private void OnPlusButtonClicked()
{
if (_model.Timing.Value < MAX_TIMING)
_model.SetTiming(_model.Timing.Value + 1);
}
private void OnMinusButtonClicked()
{
if (MIN_TIMING < _model.Timing.Value)
_model.SetTiming(_model.Timing.Value - 1);
}
private void OnAutoButtonClicked()
{
}
private void OnResetButtonClicked()
{
_model.SetTiming(0);
}
}
MVP 덤 1
개체를 모니터링 할 때, 값타입이 아니라면 null 인 경우가 있을 수 있으니 null체크를 고려해야한다.
public class View : MonoBehavior
{
public void OnPlayerChanged(PlayerData player)
{
if (player == null)
return;
_nicknameLabel.value = player.Nickname;
_levelLabel.value = player.Level.ToString();
}
}
만약 UniRX를 사용한다면 데코레이터를 사용하면 된다.
_model.Player
.Where(player => player != null)
.Subscribe(_view.OnPlayerChanged)
.AddTo(gameObject);
'🌍 Unity 연구 > 아키텍처' 카테고리의 다른 글
MVP 정리 (0) | 2021.09.20 |
---|---|
UIView (0) | 2021.09.19 |
MVC / MVP / MVVM 패턴 자료수집 (0) | 2021.09.17 |