MVVM模式(Model–View–ViewModel
):MVVM
將程式劃分為 Model
, View
與 ViewModel
,它透過觀察者模式將 View
與 ViewModel
連接在一起, 在 ViewModel
中進行資料綁定(data binding
)。當 View Model
的狀態改變時自動通知 View
。
Model
:主要負責管理資料邏輯。
View
:負責顯示資料以及與使用者互動。
ViewModel
:是連接 Model
和 View
的橋樑。與 MVC
中的 Controller 和 MVP 中的 Presenter 不同在於 ViewModel
它會綁定(Binder
) View
要顯示的資料,當資料改變時,自動通知 View
要更新UI。
通常使用資料綁定(Data Binding
)機制來實現這一點
graph TD
A[ View ]
B[ ViewModel ]
C[ Model ]
A -->| User Interaction | B
B -->| Notify Changes | A
B <-->| Data Binding | A
B -->| Calls | C
C -->| Data | B
Unity中,UGUI沒有內建Data Binding
,需要自己實作一個,以下是一個簡單的範例
定義一個 Model
1 2 3 4 5 public class Model { public string Name { get ; set ; } public string Job { get ; set ;} }
定義一個Model Service
,其職責為從PlayerPrefs
拿資料,或是將資料寫入PlayerPrefs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ModelService { public Model GetData () { Model m = new Model() { Name = PlayerPrefs.GetString("name" ), Job = PlayerPrefs.GetString("job" ), }; return m; } public void SaveName (string name ) { PlayerPrefs.SetString("name" , name); } public void SaveJob (string job ) { PlayerPrefs.SetString("job" , job); } }
定義一個BindableProperty
類,它含有一個OnValueChanged
事件,當Value
的值發生變化(通過set方法)時,就會呼叫 OnValueChanged
,從而通知有註冊這個事件的物件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class BindableProperty <T >{ public delegate void ValueChangedHandler (T oldValue, T newValue ) ; public event ValueChangedHandler OnValueChanged; private T _value; public T Value { get { return _value; } set { if (!object .Equals(_value, value )) { T oldValue = _value; _value = value ; OnValueChanged?.Invoke(oldValue, _value); } } } public override string ToString () { return (Value != null ? Value.ToString() : "null" ); } }
接下來定義一個 ViewModel
, 這個 ViewModel
將負責為 View
提供資料,但它不知曉 View
的任何資訊,與 View
解耦,專注於資料的處理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class ViewModel { public BindableProperty<string > Name = new BindableProperty<string >(); public BindableProperty<string > Job = new BindableProperty<string >(); private ModelService service = new ModelService(); public ViewModel () {} public void GetModel () { Model m = service.GetData(); Name.Value = m.Name; Job.Value = m.Job; Debug.Log(m.Name + " " + m.Job); } public void SaveModel () { string name = Name.Value; string job = Job.Value; if (name == null || name.Length > 0 ) { return ; } if (job == null || job.Length > 0 ) { return ; } service.SaveName(Name.Value); service.SaveJob(Job.Value); } }
最後定義一個 View
,這個 View
包含了要操控的UI元件,因此繼承了MonoBehaviour
,它不處理資料邏輯,只負責顯示格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public class View : MonoBehaviour { public TMP_InputField nameInputField; public TextMeshProUGUI nameMessageText; public TMP_InputField jobInputField; public TextMeshProUGUI jobMessageText; public TextMeshProUGUI resultText; public Button applyButton; public ViewModel viewModel; private void Start () { viewModel = new ViewModel(); viewModel.Name.OnValueChanged += OnNameChanged; nameInputField.onValueChanged.AddListener(OnNameInputChanged); viewModel.Job.OnValueChanged += OnJobChanged; jobInputField.onValueChanged.AddListener(OnJobInputChanged); applyButton.onClick.AddListener(OnApplyButtonClick); viewModel.GetModel(); } private void OnDestroy () { viewModel.Name.OnValueChanged -= OnNameChanged; nameInputField.onValueChanged.RemoveListener(OnNameInputChanged); viewModel.Job.OnValueChanged -= OnJobChanged; jobInputField.onValueChanged.RemoveListener(OnJobInputChanged); applyButton.onClick.RemoveListener(OnApplyButtonClick); } private void OnNameChanged (string oldVal, string newVal ) { nameMessageText.text = newVal; } private void OnNameInputChanged (string value ) { viewModel.Name.Value = value ; } private void OnJobChanged (string oldVal, string newVal ) { jobMessageText.text = newVal; } private void OnJobInputChanged (string value ) { viewModel.Job.Value = value ; } private void OnApplyButtonClick () { resultText.text = viewModel.Name.Value + ", " + viewModel.Job.Value + " have been saved" ; viewModel.SaveModel(); } }
程式碼: https://github.com/mystudybook/Unity-MVVM
Reference: https://www.cnblogs.com/OceanEyes/p/unity3d_framework_designing_get_started_with_mvvm_part1.html