返回

11.组合模式

将对象以树状结构组合,用以表现部分-全体的层次关系。组合模式让客户端在操作各个对象或组合对象时是一致的。

组合模式

将对象以树状结构组合,用以表现部分-全体的层次关系。组合模式让客户端在操作各个对象或组合对象时是一致的。

组合模式的定义

参与者说明如下:

  • Component(组件界面)
    • 定义树状结构中,每一个节点可以使用的操作方法。
  • Composite(组合节点)
    • 即根节点的盖帘
    • 会包含叶节点的对象
    • 会实现Component(组件界面)中与子节点操作有关的方法,如Add、Remove、GetChild等
  • Leaf(叶节点)
    • 不在包含任何子节点的最终节点
    • 实现Component(组件界面)中基本的行为,对于与子节点操作有关的方法可以不实现,也可以提出警告或 弹出例外。

具体实现

	// 複合體內含物件之介面
    public abstract class IComponent
    {
        protected string m_Value;

        public abstract void Operation(); // 一般操作

        // 加入節點
        public virtual void Add(IComponent theComponent)
        {
            Debug.LogWarning("子類別沒實作");
        }

        // 移除節點
        public virtual void Remove(IComponent theComponent)
        {
            Debug.LogWarning("子類別沒實作");
        }

        // 取得子節點
        public virtual IComponent GetChild(int Index)
        {
            Debug.LogWarning("子類別沒實作");
            return null;
        }
    }

    // 代表複合結構之終端物件
    public class Leaf : IComponent
    {
        public Leaf(string Value)
        {
            m_Value = Value;
        }

        public override void Operation()
        {
            Debug.Log("Leaf[" + m_Value + "]執行Operation()");
        }
    }

    // 代表複合結構的節點之行為
    public class Composite : IComponent
    {
        List<IComponent> m_Childs = new List<IComponent>();

        public Composite(string Value)
        {
            m_Value = Value;
        }

        // 一般操作
        public override void Operation()
        {
            Debug.Log("Composite[" + m_Value + "]");
            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];
        }
    }

用组合模式实现用户界面

使用工具树状查找UI组件或对象

public static class UITool
{
	private static GameObject m_CanvasObj = null; // 場景上的2D畫布物件

	public static void ReleaseCanvas()
	{
		m_CanvasObj = null;
	}

	// 找尋限定在Canvas畫布下的UI界面
	public static GameObject FindUIGameObject(string UIName)
	{
		if(m_CanvasObj == null)
			m_CanvasObj = UnityTool.FindGameObject( "Canvas" );
		if(m_CanvasObj ==null)
			return null;
		return UnityTool.FindChildGameObject( m_CanvasObj, UIName);
	}
	
	// 取得UI元件
	public static T GetUIComponent<T>(GameObject Container,string UIName) where T : UnityEngine.Component
	{
		// 找出子物件 
		GameObject ChildGameObject = UnityTool.FindChildGameObject( Container, UIName);
		if( ChildGameObject == null)
			return null;
		
		T tempObj = ChildGameObject.GetComponent<T>();
		if( tempObj == null)
		{
			Debug.LogWarning("元件["+UIName+"]不是["+ typeof(T) +"]");		
			return null;
		}
		return tempObj;
	}
	
	public static Button GetButton(string BtnName)
	{
		// 取得Canvas
		GameObject UIRoot = GameObject.Find("Canvas");
		if(UIRoot==null)
		{
			Debug.LogWarning("場景上沒有UI Canvas");
			return null;
		}
		
		// 找出對應的Button
		Transform[] allChildren = UIRoot.GetComponentsInChildren<Transform>();
		foreach(Transform child in allChildren)
		{
			if( child.name == BtnName ) 
			{
				Button tmpBtn = child.gameObject.GetComponent<Button>();
				if(tmpBtn == null)				
					Debug.LogWarning("UI原件["+BtnName+"]不是Button");
				return tmpBtn;
			}	
		}

		Debug.LogWarning("UI Canvas中沒有Button["+BtnName+"]存在");
		return null;
	}

	// 取得UI元件
	public static T GetUIComponent<T>(string UIName) where T : UnityEngine.Component
	{
		// 取得Canvas
		GameObject UIRoot = GameObject.Find("Canvas");
		if(UIRoot==null)
		{
			Debug.LogWarning("場景上沒有UI Canvas");
			return null;
		}
		return GetUIComponent<T>( UIRoot,UIName); 
	}
}

组合模式的优缺点

优点:

  • 界面与功能分离
  • 工作切分更容易
  • 界面更改不影响项目

缺点

  • 组件名称重复
  • 组件更名不易