• 设计模式(C#)——08组合模式


    推荐阅读:

          游戏通常包含许多视图。主视图中显示角色。有一个子视图,显示玩家的积分。有一个子视图,显示游戏中剩下的时间。
          可维护性应该是游戏开发过程中的主要关注点。每个视图不应具有不同的函数名称或不同的访问点。相反,你想要为每个视图提供一个统一的访问点,即相同的函数调用应该既能够访问主视图也能够访问子视图。这种统一的接入点可以使用组合设计模式。

    游戏开发中常用的设计模式之一组合模式

          组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。
          组合模式依据树形结构来组合对象,用来表示部分以及整体层次。它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
          组合模式使得用户对单个对象和组合对象的使用具有一致性。

    组合模式的要素:

    1、抽象构件(Component ):它是所有叶子构件和容器构件的共同父类,里面声明了叶子构件和容器构件的所有方法;
    2、容器构件(Composite):定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(Add)和删除(Delete)等。
    3、叶子构件(Leaf):在组合中表示叶子结点对象,叶子结点没有子结点,对于从父类中继承过来的容器构件的方法,由于它不能实现,可以抛出异常;

          此模式将每个视图放置在树状结构中,从而为每个视图提供统一的访问点。取代了需要用不同的函数来访问不同的子视图,组合模式可以用相同的函数访问任何视图。继续使用上面的列子,使用组合模式来分解游戏中的视图如下:
    在这里插入图片描述
          下面举一个Unity中组件的层级结构的例子来帮助大家更加清除的学习组合模式。在Unity中每个GameObject对象都有一个Transform组件,这个组件提供了几个和游戏对象分层操作有关的方法和变量。

    变量:

    childCount:代表子组件数量
    parent:代表父组件中的Transform对象引用

    方法:

    DetachChildren:解除所有子组件与本身的关联
    Find: 寻找子组件
    GetChild: 使用Index的方式取回子组件
    IsChildOf: 判断某个Transform对象是否为其子组件
    SetParent:设置某个Transform对象为其父组件

          再仔细分析,则可以将Unity3D的Transform类当成是一个通用类,因为它并不明显得可以察觉出其下又被再分成“目录节点”或是单纯的“单的终端节点”

          其实应该说,Transform类完全符合组合模式的需求:“让客户端在操作各个对象或组件时是一致的”。
          因此对于场景上所有的游戏对象GameObject,可以不管它们最终代表的什么,对于所有操作都能正确反应。
    下面介绍下如何使用代码实现:
    1.创建抽象构件(IComponent):

    public abstract class IComponent 
    {
        protected string m_Value;
    
        public abstract void Operation();
    
        public virtual void Add(IComponent theComponent) {}
        public virtual void Remove(IComponent theComponent) { }
        public virtual IComponent GetChild(int index) 
        {
            return null;
        }
    }
    

    2、容器构件(Composite):

    //节点类
    public class Composite : IComponent 
    {
        List<IComponent> m_Childs = new List<IComponent>();
    
        public Composite(string Value) 
        {
            m_Value = Value;
        }
    
        public override void Operation()
        {
            foreach (IComponent theComponent in m_Childs) 
            {
                theComponent.Operation();
            }
        }
    
        public override void Add(IComponent theComponent)
        {
            m_Childs.Add(theComponent);
        }
    
        public override void Remove(IComponent theComponent)
        {
            m_Childs.Remove(theComponent);
        }
    
        public override IComponent GetChild(int index)
        {
            return m_Childs[index];
        }
    }
    

    3、叶子构件(Leaf)

    //叶子类
    public class Leaf : IComponent 
    {
        public Leaf(string Value) 
        {
            m_Value = Value;
        }
    
        public override void Operation(){}
    }
    

    4.使用组合模式:

    //测试类
    public class TestComposite 
    {
        void UnitTest() 
        {
            IComponent theRoot = new Composite("Root");
    
            theRoot.Add(new Leaf("Leaf1"));
            theRoot.Add(new Leaf("Leaf2"));
    
            IComponent theChild1 = new Composite("Child1");
            theChild1.Add(new Leaf("Child1.Leaf1"));
            theChild1.Add(new Leaf("Child1.Leaf2"));
            theRoot.Add(theChild1);
    
            IComponent theChild2 = new Composite("Child2");
            theChild2.Add(new Leaf("Child2.Leaf1"));
            theChild2.Add(new Leaf("Child2.Leaf2"));
            theChild2.Add(new Leaf("Child2.Leaf3"));
            theRoot.Add(theChild2);
    
            theRoot.Operation();
        }
    }
    

    总结

    优点:

    界面与功能分离,更具移植性
    工作切分更容易,当脚本移除,就可以让UI设计交由美术和企划组装
    界面更改不影响项目:只要维持组件名称不变,界面的更改就不容易影响到游戏现有程序功能的运行。

    缺点:

    组件名称重复,如果没有将层级切分好,就容易出现该问题,在工具名称添加警告可以解决。
    组件更名不易:组件名需要通过字符串来查找,界面组件一旦不能获取,则会出现null值,和不正确的场景,应对的方法同样是在UnityTool中添加查找失败的警告。

  • 相关阅读:
    常用词汇短语
    Java中的数据结构
    Java中的设计模式
    .NET中的编译、程序调用
    常用口语
    0. Angular框架原理
    茶叶
    NPOI自定义单元格背景颜色
    ASP.NET MVC添加Action就找不到
    navicat for mysql 导入SQL Server显示中文乱码解决办法
  • 原文地址:https://www.cnblogs.com/shirln/p/10245252.html
Copyright © 2020-2023  润新知