目前已经定义的接口如下
我们还需要两个接口,一个是表现层的IController,一个是工具层的IUtility。并且目前的ICommand的接口还不够完善,我们需要Command接口能通过单例的方式获取Architecture对象。
实现IController时出现的问题 IController与MVC中的Controller是一个意思。
表现层需要向底层发送Command,监听底层系统的事件,还有一个功能,就是查询Model或者System层的一些数据,这个功能我们用IController来定义。
在FrameworkDesign——Framework——Architecture中新建IController
脚本
1 2 3 4 5 6 namespace FrameWorkDesign { public interface IController : IBelongToArchitecture { } }
由于表现层的对象时常进行创建和销毁,所以表现层的对象注册到Architecture是没有意义的,而这里定义IController
接口的意义就是标记一下这个表现层的对象是属于表现层的。
所以我们修改一下表现层,修改一下CounterViewController
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;using UnityEngine.UI;using FrameWorkDesign;namespace CounterApp { public class CounterViewController : MonoBehaviour , IController { public IArchitecture Architecture { get ; set ; } private void Start () { m_CounterModel = Architecture.GetModel<ICounterModel>(); } } }
表现层调用的Architecture.GetModel
是空的,因为我们不用CounterApp
就意味着初始化的方法MakeSureArchitecture
没有调用
所以修改Architecture
脚本,使用单例的形式确保MakeSureArchitecture
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public abstract class Architecture <T > : IArchitecture where T : Architecture <T >,new () { public static IArchitecture Interface { get { if (m_Architecture == null ) { MakeSureArchitecture(); } return m_Architecture; } } }
接着修改CounterViewController
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;using UnityEngine.UI;using FrameWorkDesign;namespace CounterApp { public class CounterViewController : MonoBehaviour , IController { public IArchitecture Architecture { get ; set ; } = CounterApp.Interface private void Start () { m_CounterModel = Architecture.GetModel<ICounterModel>(); } } }
这个时候Unity就会报错,原因是public IArchitecture Architecture { get; set; } = CounterApp.Interface
这行代码在调用的时候会自然调用一些构造函数比如new PlayerPrefStorage
,但是有一些构造函数使用了Unity自己的API(new PlayerPrefStorage
就是),这是不允许的,Unity自己的API需要确保在Start或者Awake中初始化或者说调用,但是我们不能将它移动到Start方法里面,因为架构本身不能依赖MonoBehaviour的生命周期。
最简单的方法就是用.Net4.x提供的Lazy类,但为了我们的架构能够在比较老的Unity版本中运行,我们换一种方式解决这个问题。
拆分IBelongToArchitecture 先修改IBelongToArchitecture
脚本
1 2 3 4 5 6 7 namespace FrameWorkDesign { public interface IBelongToArchitecture { IArchitecture GetArchitecture () ; } }
这样我们的Architecture的获取由原来的属性改为只能通过方法获取(get),而set部分我们使用一个新的接口
我们在FrameworkDesign——Framework——Architecture中新建ICanSetArchitecture
脚本
1 2 3 4 5 6 7 namespace FrameWorkDesign { public interface ICanSetArchitecture { void SetArchitecture (IArchitecture architecture ) ; } }
修改我们之前实现的IModel
和ISystem
,由于之前使用IArchitecture
声明属性的时候,我们的用法就是在注册的时候给属性赋值,调用Init方法的时候从属性获取值,所以这里我们让这两个接口同时继承IBelongToArchitecture
和ICanSetArchitecture
1 2 3 4 5 6 7 namespace FrameWorkDesign { public interface IModel : IBelongToArchitecture , ICanSetArchitecture { void Init () ; } }
1 2 3 4 5 6 7 namespace FrameWorkDesign { public interface ISystem : IBelongToArchitecture , ICanSetArchitecture { void Init () ; } }
修改Architecture
中的RegisterModel<T>
和RegisterSystem<T>
方法
1 2 3 4 5 6 7 8 9 10 public void RegisterModel <T >(T model ) where T : IModel { model.SetArchitecture(this ); } public void RegisterSystem <T >(T system ) where T : ISystem { system.SetArchitecture(this ); }
修改IModel和ISystem实现的类,先修改CounterModel
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 CounterModel : ICounterModel { public void Init () { var storage = m_Architecture.GetUtility<IStorage>(); Count.Value = storage.LoadInt("COUNTER_COUNT" , 0 ); Count.OnValueChanged += count => { storage.SaveInt("COUNTER_COUNT" , count); }; } private IArchitecture m_Architecture; public IArchitecture GetArchitecture () { return m_Architecture; } public void SetArchitecture (IArchitecture architecture ) { m_Architecture = architecture; } public BindableProperty<int > Count { get ; } = new BindableProperty<int >() { Value = 0 }; }
再修改AchievementSystem
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 public class AchievementSystem : IAchievementSystem { private IArchitecture m_Architecture; public IArchitecture GetArchitecture () { return m_Architecture; } public void SetArchitecture (IArchitecture architecture ) { m_Architecture = architecture; } public void Init () { var counterModel = m_Architecture.GetModel<ICounterModel>(); var previousCount = counterModel.Count.Value; counterModel.Count.OnValueChanged += newCount => { if (previousCount<10 && newCount >= 10 ) { Debug.Log("点击10次" ); }else if (previousCount < 20 && newCount >= 20 ) { Debug.Log("点击20次" ); } previousCount = newCount; }; } }
最后修改我们之前实现IController
的地方,也就是CounterViewController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CounterViewController : MonoBehaviour , IController { private ICounterModel m_CounterModel; public IArchitecture GetArchitecture () { return CounterApp.Interface; } private void Start () { m_CounterModel = GetArchitecture().GetModel<ICounterModel>(); } }
我们可以看到,和之前声明属性不一样,我们这里实现public IArchitecture GetArchitecture()
仅仅是一个方法,这个方法在Start里面调用,解决了之前的问题,而且我们把Get和Set分离成两个接口之后,IModel和ISystem只需要实现这两个接口就不会破坏之前的设计,而IController接口的实现只需要实现Get部分即可
用抽象类减少IModel和ISystem的样板代码 我们可以看到因为IModel和ISystem多实现了两个接口,总是要写这些接口就会造成样板代码,我们把Model和System改成抽象类来解决这个问题
修改IModel
脚本
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 namespace FrameWorkDesign { public interface IModel : IBelongToArchitecture , ICanSetArchitecture { void Init () ; } public abstract class AbstractModel : IModel { private IArchitecture m_Architecture; public IArchitecture GetArchitecture () { return m_Architecture; } public void SetArchitecture (IArchitecture architecture ) { m_Architecture = architecture; } void IModel.Init() { OnInit(); } protected abstract void OnInit () ; } }
修改ISystem脚本
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 namespace FrameWorkDesign { public interface ISystem : IBelongToArchitecture , ICanSetArchitecture { void Init () ; } public abstract class AbstractSystem : ISystem { private IArchitecture m_Architecture; public IArchitecture GetArchitecture () { return m_Architecture; } public void SetArchitecture (IArchitecture architecture ) { m_Architecture = architecture; } void ISystem.Init() { OnInit(); } protected abstract void OnInit () ; } }
修改CounterModel
,删除掉之前实现接口的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CounterModel : AbstractModel ,ICounterModel { protected override void OnInit () { var storage = GetArchitecture().GetUtility<IStorage>(); Count.Value = storage.LoadInt("COUNTER_COUNT" , 0 ); Count.OnValueChanged += count => { storage.SaveInt("COUNTER_COUNT" , count); }; } public BindableProperty<int > Count { get ; } = new BindableProperty<int >() { Value = 0 }; }
修改AchievementSystem
,删除掉之前实现接口的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class AchievementSystem : AbstractSystem , IAchievementSystem { protected override void OnInit () { var counterModel = GetArchitecture().GetModel<ICounterModel>(); var previousCount = counterModel.Count.Value; counterModel.Count.OnValueChanged += newCount => { if (previousCount<10 && newCount >= 10 ) { Debug.Log("点击10次" ); }else if (previousCount < 20 && newCount >= 20 ) { Debug.Log("点击20次" ); } previousCount = newCount; }; } }