• Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)


    『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率。 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则。

    组件化设计的思路

    不管是开发客户端应用程序还是开发服务器端应用程序,『组件』这个词我们并不陌生。不管是在iOS中的xib,还是在AngularJS的Component,或者后端开发的 User Control,可复用的组件是面向对象开发的基础。所以在Unity 3D 框架设计时,组件化是核心的概念。那么如何去设计SubView和SubViewModel,我总结出几条原则:

    • 当一个功能被不同的场合频繁用到,建议将这个功能抽象成SubView(SubViewModel)
    • SubView(SubViewModel)应该保持高内聚,低耦合原则
    • SubViewModel不应该处理具体的业务逻辑,它很单纯,可通过委托Delegate的方式交由外部处理

    构建SubView和SubViewModel

    假设现在有如下一个需求,需要绑定角色的信息到头像上,如下图所示:

    这是一个很常见的需求,创建一个MonoBehaviour,定义Public的变量并引用这些控件,最后再将这个MonoBehaviour附加到GameObject上,很快就能完成。当然,我不能说这样的实施是错误的,毕竟我们只要保证运行正确就可以了。

    看到左上角的勋章吗,这个勋章会在不同的场景出现,我们优先把它考虑成一个SubView(BadgeView),也就是最外层的FaceBoxView里嵌套了一个BadgeView

    public class FaceBoxView:UnityGuiView<FaceBoxViewModel>
    {
    	public Text nameText;
    	public Text levelText;
    	public Image faceImage;
    	public BadgeView badgeView;
    }
    

    我们在分析一下BadgeView需要什么数据?它需要武器的Icon和属性颜色,所以我们抽象出一个Badge的DataModel:

    public class Badge
    {
        public string Icon { get; set; }
        public string ElementColor { get; set; }
    }
    

    所以对于FaceBoxViewModel而言,它为FaceBoxView服务。FaceBoxView需要什么数据,它就提供什么数据。显然它需要提供Name,Level,Face以及Badge组件的DataModel:

    public class FaceBoxViewModel:ViewModelBase
    {
        public readonly BindableProperty<string> Name=new BindableProperty<string>();
        public readonly BindableProperty<int> Level=new BindableProperty<int>();
        public readonly BindableProperty<string> Face=new BindableProperty<string>();
        public readonly BindableProperty<Badge> Badge=new BindableProperty<Badge>();
    
        public override void OnStartReveal()
        {
            base.OnStartReveal();
            Initialization();
        }
    
        public void Initialization()
        {
            Name.Value = "比尔";
            Level.Value = 9;
            Face.Value = "Avatar204_Face";
            Badge.Value = new Badge() {Icon = "Icon_WeaponRod", ElementColor = "1CB9FFFF"};
        }
    }
    

    因为Badge是BindableProperty类型对象,特点是当Badge Value改变时,触发的OnValueChanged事件就可以给BadgeViewModel传递数据,从而初始化BadgeView:

        protected override void OnInitialize()
        {
            base.OnInitialize();
            Binder.Add<string>("Name",OnNamePropertyVlaueChanged);
            Binder.Add<int>("Level",OnLevelPropertyValueChanged);
            Binder.Add<string>("Face",OnFacePropertyValueChanged);
            Binder.Add<Badge>("Badge",OnBadgePropertyValueChanged);
        }
    
        private void OnBadgePropertyValueChanged(Badge oldValue, Badge newValue)
        {
            badgeView.BindingContext = new BadgeViewModel() ;
            badgeView.BindingContext.Initialization(newValue);
    
        }
    

    我们可以看到,组件化的实施从代码量上是变得复杂了,组件的颗粒度越细,那么嵌套的层次就越深,如果某个功能只出现一次,并且不会被复用,那么我不推荐将它变为一个SubView(SubViewModel)

    小结

    本文为大家介绍怎样将组件化模式思想引入到Unity 3D中,在我的uMVVM框架中,组件化是核心,就像用户控件一样,随拿随走,它们保持高度独立,这样的好处是不会产生紧耦合。还值得一提的是,其实Unity 3D本身的开发模式就是基于组件化开发的。只要创建一个MonoBehaviour组件然后附加到GameObject上就能正常运行。但需要注意的事,如果没有好的约束,一个GameObject上就会附加好多个MonoBehaviour,GameObject的子GameObject也会附加很多个MonoBehaviour,久而久之,整个层级结构会变得异常复杂和难以维护。uMVVM的理念是只需要一个View,View是唯一的入口,并且View可以是非常复杂,里面维护了所有的SubView,所以换UI也好,换功能也罢,只要关注于对应的View即可。
    源代码托管在Github上,点击此了解

  • 相关阅读:
    关于数组的算法-编程之美读后感-1
    java学习笔记之线程1
    java学习笔记之IO一()
    java学习笔记之泛型
    java学习笔记之正则表达式
    Thinking in java学习笔记之String的不可变性
    Thinking in java学习笔记之map的应用
    Thinking in java学习笔记之set
    scrapy之中间件
    Linux之Redis-redis哨兵集群详解
  • 原文地址:https://www.cnblogs.com/OceanEyes/p/set_up_subview_and_subviewmodel_part1.html
Copyright © 2020-2023  润新知