我是靠谱客的博主 瘦瘦水杯,最近开发中收集的这篇文章主要介绍迭代器模式 - Unity迭代器模式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 迭代器模式
    • 结构
    • 实现
    • 应用场景
    • 优缺点
    • 与其他模式的关系

迭代器模式

迭代器模式是对象行为型模式,它提供一个对象来顺序访问聚合对象中的元素(遍历元素的算法),且不暴露底层实现。

集合是编程中非常常见的数据结构之一。对于不同数据类型所需要的不同的遍历方式。但大多数客户端并不关心数据存储的方式。所以由于集合的遍历方式的不同,我们需要将集合遍历的算法,从集合中抽取出来,而抽取的部分,就是迭代器。

迭代器通常会提供获取集合元素的基本方法。客户端通过不断调用此方法,直至遍历结束。在 C# 中 foreach 就是对于迭代器遍历元素的具体实现。foreach 需要集合类继承 IEnumerable 接口,IEnumerable 只有一个方法就是返回 集合枚举器(即是迭代器)IEnumerator

结构

在这里插入图片描述
说明

  • 抽象迭代器(Iterator)- 接口需要声明遍历聚合操作:一个获得元素的方法,一个获得当前位置的方法。
  • 具体迭代器(Concrete Iterator)- 实现具体遍历的算法
  • 抽象聚合(Aggregate)- 接口需声明一个迭代器接口(返回值为迭代器),其余集合的常见操作可以有选择的声明
  • 具体聚合(Concrete Aggregate)- 实现抽象方法,也可以自行实现一些具体的集合操作。

说明
在 C# 中集合类几乎均是采用迭代器模式,如 List,Queue,Stack,Dictionary等。
迭代器接口为 IEnumerator 和 泛型接口 IEnumerator<T>
聚合接口为IEnumerable 和 泛型接口 IEnumerable<T>

我建议自定义实现的集合,若无特殊情况,都去实现 IEnumerable<T>IEnumerator<T> 这两个泛型接口。因为 C# 中的许多原生的特性和函数都是围绕着两个接口实现的,当我们去实现这两个接口时,有许多的 C# 特性可以直接套用即可。

foreach 遍历 和 Linq 语句等

实现

这里我们将直接套用泛型接口 IEnumerableIEnumerator

这里来我们封装 GameObject 的集合

游戏对象枚举器(具体迭代器)

    public class GameObjectEnum : IEnumerator<GameObject>
    {
        private IList<GameObject> _list;
        private int _index = -1;

        public GameObjectEnum(IList<GameObject> list)
        {
            _list = list;
        }

        public bool MoveNext()
        {
            _index++;
            return _index < _list.Count;
        }

        public void Reset() => _index = -1;

        public GameObject Current
        {
            get
            {
                try
                {
                    return _list[_index];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new IndexOutOfRangeException();
                }
            }
        }

        object IEnumerator.Current => Current;

        public void Dispose() { }
    }

游戏对象集合(具体聚合类)

    public class GameObjectList : IEnumerable<GameObject>
    {
        private IList<GameObject> _list;

        public int Count => _list.Count;
    
        public GameObject this[int index]
        {
            get => _list[index];
            set => _list[index] = value;
        }

        public GameObjectList()
        {
            _list = new List<GameObject>();
        }

        public void Add(GameObject item) => _list.Add(item);

        public void Remove(GameObject item) => _list.Remove(item);

        public void RemoveAt(int index) => _list.RemoveAt(index);

        public GameObject GetRandom() => _list[Random.Range(0, _list.Count)];
    
        public IEnumerator<GameObject> GetEnumerator()
        {
            return new GameObjectEnum(_list);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

调用端

    public class IteratorExample : MonoBehaviour
    {
        [SerializeField] private GameObject[] _gameObjects;
        private GameObjectList _list;

        private void Start()
        {
            _list = new GameObjectList();
            
            foreach (var go in _gameObjects)
            {
                _list.Add(go);
            }
        }

        private void OnGUI()
        {
            GUILayout.BeginArea(new Rect(10, 10, 300, 1000));
            //随机获得一个对象
            if (GUILayout.Button("Random", GUILayout.Height(120)))
                _list.GetRandom().GetComponent<MeshRenderer>().material.color = Color.red;
            
            //遍历对象,使用协程来达到可视化效果
            if (GUILayout.Button("Foreach", GUILayout.Height(120)))
            {
                if (_coroutine != null)
                {
                    foreach (var go in _list)
                    {
                        go.GetComponent<MeshRenderer>().material.color = Color.white;
                    }
                    
                    StopCoroutine(_coroutine);
                }
                _coroutine = StartCoroutine(nameof(ForeachList));
            }
            
            //还原为白色
            if (GUILayout.Button("Reduction", GUILayout.Height(120)))
            {
                foreach (var go in _list)
                {
                    go.GetComponent<MeshRenderer>().material.color = Color.white;
                }
            }
                
            GUILayout.EndArea();
        }

        private Coroutine _coroutine;
        private IEnumerator ForeachList()
        {
            foreach (var go in _list)
            {
                yield return new WaitForSeconds(0.4f);
                
                go.GetComponent<MeshRenderer>().material.color = Color.green;
            }
        }
    }

在这里插入图片描述

这里可以自行去测试一下,并且由于实现了 IEnumerable<T> 同时也是可以使用 Linq 语句查询的

应用场景

  • 当集合为复杂的数据类型时,需要隐藏其实现
  • 希望动态的切换遍历算法时,如 DFS遍历树,BFS遍历树等。

优缺点

优点

  • 复杂的遍历过程抽取成单独的类,满足单一职责原则
  • 当使用新的迭代算法时,不会影响原来的类
  • 支持动态切换迭代算法

缺点

  • 迭代器的遍历不如直接遍历高效
  • 会提升系统复杂度

与其他模式的关系

  • 组合模式可以使用迭代器模式进行遍历
  • 使用工厂模式可以创建不同迭代器

最后

以上就是瘦瘦水杯为你收集整理的迭代器模式 - Unity迭代器模式的全部内容,希望文章能够帮你解决迭代器模式 - Unity迭代器模式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部