您的位置:首页 > 编程语言 > C#

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

2012-04-24 14:44 330 查看
此测试代码包含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:所谓模式,即代码的组织方式,模式源于实践和总结。同时,模式也是一种思想,是人们对于程序对象的一种认识和剖析...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: