组件模式代码实践(C#版本)

此测试代码包含3个基本类:

class EntityBase:实体基类

class ComponentBase:组件基类

class Event:消息类

组合模式的关键在于:(1)实体通过组件实现功能,组件依赖于实体而存在;(2)通过事件驱动组件的各种行为。

EntityBase代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    class EntityBase
    {
        // 组件列表,未实现RTTI,故用string做索引
        // 如果有RTTI,可以直接存储List<ComponentBase>,并且大多是这么做的
        Dictionary<string, ComponentBase> ComponentArray = new Dictionary<string, ComponentBase>();

        // 通过此函数将消息分发给各个Component,各个Component各自处理此消息
        // 通过DisptachEvetn,每个Compoent都会收到此消息,但是否处理此消息,由各组件自己决定
        public virtual bool DispatchEvent(Event evt)
        {
            bool bHandled = false;
            foreach (ComponentBase comp in ComponentArray.Values)
            {
                bool ret = comp.OnEvent(evt);
                bHandled = (bHandled || ret);
            }
            if (bHandled == false)
                Console.WriteLine("Receive an unhandled event: id = " + evt.EventID.ToString());

            return bHandled;
        }

        public bool AddComponent(string compName, ComponentBase compObject)
        {
            if (compObject == null)
            {
                Console.Write("AddComponent Failed, Component.Name=" + compName);
                return false;
            }

            ComponentArray.Add(compName, compObject);
            compObject.OnAttachToEntity(this);
            OnComponentAttached(compObject);

            return true;
        }

        public bool RemoveComponent(string compName)
        {
            if (!ComponentArray.ContainsKey(compName))
            {
                Console.Write("RemoveComponent Failed, Component.Name=" + compName);
                return false;
            }

            ComponentArray[compName].OnDetachFromEntity(this);
            OnComponentDetached(ComponentArray[compName]);
            ComponentArray.Remove(compName);
            return true;
        }

        public virtual void OnComponentAttached(ComponentBase compObject)
        {
        }

        public virtual void OnComponentDetached(ComponentBase compObject)
        {
        }

    }
}

ComponentBase代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    class ComponentBase
    {
        protected delegate void EventHandleFunction(Event evt);

        private EntityBase Owner = null;
        // 事件映射表
        private Dictionary<int, EventHandleFunction> EventHandlerMap = new Dictionary<int, EventHandleFunction>();

        public virtual bool OnEvent(Event evt)
        {
            EventHandleFunction function = null;
            if(EventHandlerMap.TryGetValue(evt.EventID, out function) == false)
            {
                return false;
            }

            if (function == null)
                return false;

            function(evt);
            return true;
        }

        public virtual void OnAttachToEntity(EntityBase ety)
        {
            Owner = ety;
        }

        public virtual void OnDetachFromEntity(EntityBase ety)
        {
            Owner = null;
        }

        // 注册事件处理函数,同一事件注册两次,则后面的覆盖前面的
        protected void RegisterEvent(int eventID, EventHandleFunction handlerFunc)
        {
            if (EventHandlerMap.ContainsKey(eventID))
                EventHandlerMap.Remove(eventID);
            EventHandlerMap.Add(eventID, handlerFunc);
        }

        protected void UnregiterEvent(int eventID)
        {
            if (EventHandlerMap.ContainsKey(eventID))
                EventHandlerMap.Remove(eventID);
        }
    }
}

Event代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    class Event
    {
        public int EventID = -1;
        public ArrayList EventArgs = new ArrayList();

        public void PushUserData<T>(T data)
        {
            EventArgs.Add(data);
        }

        public T GetUserData<T>(int index)
        {
            if (index >= EventArgs.Count)
            {
                Console.Write("GetUserData Error!");
                return default(T);
            }
            return (T)EventArgs[index];
        }
    }
}

测试代码包括Main.cs、一个继承自ComponentBase的组件TestComponent和一个事件定义的类EventDefines。

EventDefines代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    public enum EventDefines
    {
        Event_01 = 0,
        Event_02,
        Event_03,
    }
}

TestComponent代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    class TestComponent : ComponentBase
    {
        public override void OnAttachToEntity(EntityBase ety)
        {
            base.OnAttachToEntity(ety);

            // 注册事件响应函数
            RegisterEvent((int)EventDefines.Event_01, DealEvent01);
            RegisterEvent((int)EventDefines.Event_03, DealEvent03);
        }

        public override void OnDetachFromEntity(EntityBase ety)
        {
            base.OnDetachFromEntity(ety);
        }

        private void DealEvent01(Event evt)
        {
            string evtData = evt.GetUserData<string>(0);
            Console.WriteLine("TestComponent Handle Event: ID = " + evt.EventID.ToString());
            Console.WriteLine("TestComponent Handle Event: Data = " + evtData);
        }

        private void DealEvent03(Event evt)
        {
            float evtData = evt.GetUserData<float>(0);
            Console.WriteLine("TestComponent Handle Event: ID = " + evt.EventID.ToString());
            Console.WriteLine("TestComponent Handle Event: Data = " + evtData);
        }
    }
}

Main.cs代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestComponentModel
{
    class Program
    {
        static void Main(string[] args)
        {
            // 构造一个EntityBase对象
            EntityBase ety = new EntityBase();
            // 添加TestComponent组件,可以移到EntityBase的继承类的构造函数中
            TestComponent testComp = new TestComponent();
            ety.AddComponent("TestComponent", testComp);

            // 发送消息Event_01
            Event evt1 = new Event();
            evt1.EventID = (int)EventDefines.Event_01;
            evt1.PushUserData<string>("SomeData For Event01");
            ety.DispatchEvent(evt1);

            // 发送消息Event_02
            Event evt2 = new Event();
            evt2.EventID = (int)EventDefines.Event_02;
            evt2.PushUserData<string>("SomeData For Event02");
            ety.DispatchEvent(evt2);

            // 发送消息Event_03
            Event evt3 = new Event();
            evt3.EventID = (int)EventDefines.Event_03;
            evt3.PushUserData<float>(0.123f);
            ety.DispatchEvent(evt3);

            Console.Read();
        }
    }
}

 运行结果截图:

组合模式是实用性很强的一种设计模式,目前在各种游戏代码中广泛存在,熟练运用此模式可以使代码简洁高效、可读易修改并且查错方便。

本例子所提供的代码只是测试代码,若想应用于项目,需根据实际情况进行一些修改。不过,改来改去,思想始终不变。

PS:所谓模式,即代码的组织方式,模式源于实践和总结。同时,模式也是一种思想,是人们对于程序对象的一种认识和剖析...

原文地址:https://www.cnblogs.com/sifenkesi/p/2468060.html