组合模式

前言

组合模式称为整体部分模式,主要是表现对象层次具备整体和部分,呈树形结构,且要求具备统一行为。

1.架构引擎时的组合模式

架构游戏引擎是离不开组合模式的,这里以Unity为例子,用组合模式简单表达一下如何架构出游戏引擎,首先我们定义出抽象组件类,组件类里应该有位置和锚点等等,具体代码如下:

    public static class Global
    {
        public static uint index = 0;
    }

    public struct Size
    {
        public uint x;
        public uint y;
    }

    public struct Point
    {
        public int x;
        public int y;
    }

    public enum Anchor:byte
    {
        LeftTop,
        CenterTop,
        RightTop,
        LeftCenter,
        Center,
        RightCenter,
        LeftBottom,
        CenterBottom,
        RightBottom
    }

    public abstract class GameComponent
    {
        protected uint index;//组件编号
        protected string name;//组件名字
        protected Point point;//位置
        protected Size size;//大小
        protected Anchor anchor;//锚点
        protected List<GameComponent> gameComponents;

        public GameComponent(string name,Point point,Size size,Anchor anchor)
        {
            this.index = Global.index;
            this.name = name;
            this.point = point;
            this.size = size;
            this.anchor = anchor;
            gameComponents = new List<GameComponent>();
            Global.index = Global.index + 1;
        }

        public void ShowGameComponent()
        {
            
        }

        public void HideGameComponent()
        {
            
        }

        public void Show()
        {
            ShowGameComponent();
            foreach (GameComponent gameComponent in gameComponents)
            {
                gameComponent.Show();
            }
        }

        public void Hide()
        {
            HideGameComponent();
            foreach (GameComponent gameComponent in gameComponents)
            {
                gameComponent.Hide();
            }
        }
        
        public void AddGameComponent(GameComponent gameComponent)
        {
            gameComponents.Add(gameComponent);
        }

        public void RemoveGameComponent(uint index)
        {
            foreach (GameComponent gameComponent in gameComponents)
            {
                if (gameComponent.index == index)
                {
                    try
                    {
                        gameComponents.Remove(gameComponent);
                        break;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                }
            }
        }

        public void RemoveGameComponent(GameComponent gameComponent)
        {
            try
            {
                gameComponents.Remove(gameComponent);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
    }

    public abstract class ButtonComponent:ImageComponent
    {
        public Action OnClick;
        
        public Action OnHover;

        public Action OnExit;
        
        public ButtonComponent(Action OnClick, Action OnHover, Action OnExit, string                 
           name, Point point, Size size,Anchor anchor) : base(name, point, size, anchor)
        {
            this.OnClick = OnClick;
            this.OnHover = OnHover;
            this.OnExit = OnExit;
        }
    }

    public abstract class ImageComponent:GameComponent
    {
        public ImageData imageData;
        public ImageComponent(ImageData imageData, string                 
           name, Point point, Size size,Anchor anchor) : base(name, point, size, anchor)
        {
            this.imageData = imageData;
        }
    }

这里只是简单的讲解了实现原理,接下来使用框架模拟出一个界面,伪代码如下:

    FormComponent root = new FormComponent(.....);
    MenuComponent menu = new MenuComponent(.....);
    menu.AddGameComponent(new Button(.....));
    menu.AddGameComponent(new Button(.....));
    menu.AddGameComponent(new Button(.....));
    root.AddGameComponent(new Button(.....));
    root.AddGameComponent(new Image(.....));
    root.AddGameComponent(new Image(.....));
    root.AddGameComponent(menu);
    root.Show();

设计的时候建议把所有组件共有的部分写在GameComponent,但是按钮组件就需要另外加一些事件,所以要另外加一个ButtonComponent抽象类,这个方式在组合模式里叫做安全组合模式。有安全组合模式这个名字说明组合模式不仅仅只有一种,把所有接口都定义在GameComponent里叫透明组合模式。

2.如何实现可视化配置

可能大家看到这里,会说这个也太low了,Unity是可视化界面去创建出不同的界面,可视化配置说明代码里是没有把界面写死的,说明我们在使用Unity的时候,可能背地里生成了一个配置文件,读取这个临时的配置文件创建出不同的界面,伪代码如下:

    public class NodeComponentData
    {
        private ComponentType componentType;
        protected string name;//组件名字
        protected Point point;//位置
        protected Size size;//大小
        protected Anchor anchor;//锚点
        private List<NodeComponentData> nodeComponentDatas;

        public GameComponent InitGameComponents()
        {
            GameComponent rootComponent = new GameComponentFactory(componentType, name, point, size, anchor);
            foreach (NodeComponentData nodeComponentData in nodeComponentDatas)
            {
                rootComponent.AddGameComponent(nodeComponentData.InitGameComponents());
            }
            return rootComponent;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            NodeComponentData tmpData = ConfigMgr.Load();
            tmpData.InitGameComponents();
        }
    }

其实从配置文件转换成这个NodeComponentData类时,应该把这个类也设计成完全组合的模式,这里只是简单的介绍一下大概的思想,然后我们调用InitGameComponents就可以把界面的层级关系创建出来了,InitGameComponents函数就是使用递归的思想去把组件层级表达出来的。

总结

1.透明,安全组合模式的优缺点

系统绝大多数层次具备相同的公共行为时,采用透明组合模式也许会更好(代价:为剩下少数层次节点引入不需要的方法);而如果当系统各个层次差异性行为较多或者树节点层次相对稳定(健壮)时,采用安全组合模式,所以安全组合模式符合接口最小,透明组合模式符合里氏替换原则。

2.组合模式的使用场景

1)游戏公会里面复杂的玩家职位关系。

2)游戏引擎组件之间的设计方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值