我们之前在制作强化界面时,点击切换飞机按钮属性界面就会跟着改变。两个部分是在StrengthenView
内进行联系的。
1 2 3 4 5 6 7 8 9 10 11
| [BindPrefab(Path.STRENGTHEN_VIEW)] public class StrengthenView : ViewBase { protected override void InitChild() { SwitchPlayer switchPlayer = UIUtil.Get("Switchplayer").Go.AddComponent<SwitchPlayer>(); PlaneProperty planeProperty = UIUtil.Get("Property").Go.AddComponent<PlaneProperty>();
switchPlayer.OnSwitchAction(planeProperty.UpdataId); } }
|
这明显不符合MVC分离的原则,一方面每个需要刷新的事件都要写一个Action,另一方面就是增加了耦合性。
IViewUpdate
使用接口可以很灵活,没有继承ViewBase
的Mono类,只要继承了这个接口,也可以被ViewBase
缓存并调用接口方法。
1 2 3 4
| public interface IViewUpdate { void ViewUpdate(); }
|
让IView
继承IViewUpdate
ViewBase
修改ViewBase
,让它缓存IViewUpdate
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
| public abstract class ViewBase : MonoBehaviour, IView { private List<IViewUpdate> _viewUpdates; public virtual void Init() { InitChild(); GetAllSubView(); InitAllSubView(); InitUpdateObjects(); AddUpdateAction(); } private void InitUpdateObjects() { _viewUpdates = transform.GetComponentsInChildren<IViewUpdate>().ToList();
} private void InitAllSubView() { foreach (ViewBase view in _views) { view.Init(); } } private void AddUpdateAction() { foreach (Button button in GetComponentsInChildren<Button>()) { button.onClick.AddListener(UpdateAction); } } private void UpdateAction() { foreach (IViewUpdate viewUpdate in _viewUpdates) { viewUpdate.ViewUpdate(); } } public virtual void ViewUpdate() { } }
|
注意ViewBase
实现IViewUpdate
接口时实现的是虚方法并且是空的,这样就能避免递归调用的问题(GetComponentsInChildren<IViewUpdate>
包含ViewBase
自身)
重构强化界面逻辑
在强化界面中,属性更新的部分是需要动态刷新的。
PlaneProperty
删掉PlaneProperty
的UpdateId
方法,并删除缓存item的列表
PropertyItem
让PropertyItem
继承IViewUpdate
1 2 3 4 5 6 7 8
| public class PropertyItem : MonoBehaviour, IViewUpdate { public void ViewUpdate() { UpdatePlaneId(GameStateModel.Instance.SelectedPlaneId); } }
|
StrengthenView
1 2 3 4 5 6 7 8 9
| [BindPrefab(Path.STRENGTHEN_VIEW)] public class StrengthenView : ViewBase { protected override void InitChild() { UIUtil.Get("Switchplayer").Go.AddComponent<SwitchPlayer>(); UIUtil.Get("Property").Go.AddComponent<PlaneProperty>(); } }
|
SwitchPlayer
修改SwitchPlayer
,删掉_onSwitch
,并删掉Switch
和OnSwitchAction
方法中对_onSwitch
引用的部分。
引入Model层
在之前我们声明的IDataMemory
、DataMgr
等都是从存档中交互,我们还需要在运行时进行交互的数据层。就是Model层。
GameStateModel
这里的Model是一个单例
1 2 3 4
| public class GameStateModel : NormalSingleton<GameStateModel> { public int SelectedPlaneId { get; set; } }
|
SwitchPlayer
1 2 3 4 5 6
| private void Switch(ref int id,int direction) { UpdateId(ref id,direction); UpdateSprite(id); GameStateModel.Instance.SelectedPlaneId = id; }
|
IView接口分离
通过前面的修改,我们实现了强化界面下所有的Button都能刷新界面中实现了IViewUpdate
的UI元素的功能。
但是还有一个问题,PropertyItem
的初始化依然没有被统一调用。导致一开始打开界面时没有办法刷新PropertyItem,同时PropertyItem
并没有继承ViewBase
,也就没有Init
生命周期。
我们把IView
接口分离,让没有继承ViewBase
的UI元素可以选择性地继承初始化接口,从而把自己的初始化逻辑交出去。
新建IViewInit
、IViewShow
、IViewHide
1 2 3 4
| public interface IViewInit { void Init(); }
|
1 2 3 4
| public interface IViewShow { void Show(); }
|
1 2 3 4
| public interface IViewHide { void Hide(); }
|
修改IView
1 2 3
| public interface IView : IViewUpdate, IViewInit, IViewShow, IViewHide { }
|
第二次重构ViewBase
既然IView
被分离了,我们就必须再次重构ViewBase
,现在ViewBase是UI的主层逻辑才继承的,一些小的UI元素只需要选择性地继承上面分离出来的接口就可以了。
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| using System.Collections.Generic; using UnityEngine;
public abstract class ViewBase : MonoBehaviour, IView { private UIUtil m_UIUtil; private List<IViewUpdate> _viewUpdates; private List<IViewInit> _viewInits; private List<IViewShow> _viewShows; private List<IViewHide> _viewHides; protected UIUtil UIUtil { get { if (m_UIUtil == null) { m_UIUtil = gameObject.AddComponent<UIUtil>(); m_UIUtil.Init(); } return m_UIUtil; } } public virtual void Init() { InitChild(); GetAllSubView(); InitAllSubView(); } protected abstract void InitChild(); private void GetAllSubView() { _viewInits = new List<IViewInit>(); _viewShows = new List<IViewShow>(); _viewHides = new List<IViewHide>(); _viewUpdates = new List<IViewUpdate>(); InitInterface(); } private void InitInterface() { InitViewInterface(_viewInits); InitViewInterface(_viewShows); InitViewInterface(_viewHides); InitViewInterface(_viewUpdates); } private void InitViewInterface<T>(List<T> views) { foreach (Transform trans in transform) { if (trans.TryGetComponent(out T view)) { views.Add(view); } } } private void InitAllSubView() { foreach (var view in _viewInits) { view.Init(); } } public virtual void Hide() { foreach (var view in _viewHides) { view.Hide(); } gameObject.SetActive(false); }
public virtual void Show() { gameObject.SetActive(true); foreach (var view in _viewShows) { view.Show(); } UpdateFun(); } public virtual void UpdateFun() { foreach (IViewUpdate viewUpdate in _viewUpdates) { viewUpdate.UpdateFun(); } } public Transform GetTrans() { return transform; } }
|
删除掉HashSet<ViewBase> _views
,添加_viewInits
、_viewShows
、_viewHides
修改GetAllSubView
、InitAllSubView
、Show
、Hide
方法,添加InitViewInterface
方法
修改PropertyItem
此时让PropertyItem
继承IViewShow
,并实现Show
方法
1 2 3 4 5 6 7 8 9
| public class PropertyItem : MonoBehaviour, IViewUpdate, IViewShow { public void Show() { int id = DataMgr.Instance.Get<int>(DataKeys.PLANE_ID); UpdatePlaneId(id); } }
|