意圖
將對象組合成樹形結構以表示“部分-整體”的層次結構。Composite模式使得用戶對單個對象和組合對象的使用具有一致性。
場景
我們知道,一個網絡游戲通常會有多個游戲大區。每一個游戲大區會有很多游戲服務器(一個游戲大區就是一組游戲服務器)。每一個游戲服務器上會有不同的服務(可以是多個服務)。這是一個明顯的部分-整體關系,假設我們現在需要制作一個服務器管理工具,用於顯示所有大區、服務器以及服務的信息,並且能開啟這些服務(可以是單獨開啟一個服務,也可以是開啟整個服務器上的所有服務,也可以是開啟整個大區的所有服務)。
可以看到,游戲服務器和游戲大區都是一個組合對象,而游戲服務是最底層的節點。客戶端在開啟一個游戲大區服務的時候,必須和游戲服務器以及游戲服務進行依賴,而在開啟游戲服務器上所有服務的時候,必須和游戲服務進行依賴。試想一下,如果一個公司的總裁在管理上不但需要和各總監以及經理進行溝通,還有和底層的員工溝通,那麼總裁是不是會太忙碌了一點?由此,我們引入組合模式,使組合對象和單個對象具有一樣的表現形式。
示例代碼
using System;
using System.Collections.Generic;
using System.Text;
namespace CompositeExample
{
class Program
{
static void Main(string[] args)
{
Element server1 = new GameServer("GS1", "192.168.0.1");
server1.Add(new GameService("Lobby1", 1, "S5Lobby1"));
server1.Add(new GameService("Gate1", 2, "S5Gate1"));
server1.Add(new GameService("DataExchange1", 3, "S5DataExchange1"));
server1.Add(new GameService("Rank1", 4, "S5Rank1"));
server1.Add(new GameService("Log1", 5, "S5Log1"));
Element server2 = new GameServer("GS2", "192.168.0.2");
server2.Add(new GameService("Lobby2", 1, "S5Lobby2"));
server2.Add(new GameService("Gate2", 2, "S5Gate2"));
server2.Add(new GameService("DataExchange2", 3, "S5DataExchange1"));
server2.Add(new GameService("Rank2", 4, "S5Rank2"));
server2.Add(new GameService("Log2", 5, "S5Log2"));
Element area = new GameArea("電信區");
area.Add(server1);
area.Add(server2);
area.Display();
area.Start();
area.Stop();
}
}
abstract class Element
{
protected string name;
public Element(string name)
{
this.name = name;
}
public abstract void Add(Element element);
public abstract void Remove(Element element);
public abstract void Display();
public abstract void Start();
public abstract void Stop();
}
class GameService : Element, IComparable<GameService>
{
private int serviceType;
private string serviceName;
public GameService(string name, int serviceType, string serviceName)
: base (name)
{
this.serviceName = serviceName;
this.serviceType = serviceType;
}
public override void Add(Element element)
{
throw new ApplicationException("xxx");
}
public override void Remove(Element element)
{
throw new ApplicationException("xxx");
}
public override void Display()
{
Console.WriteLine(string.Format("name:{0},serviceType:{1},serviceName:{2}", name, serviceType, serviceName));
}
public override void Start()
{
Console.WriteLine(string.Format("{0} started", name));
}
public override void Stop()
{
Console.WriteLine(string.Format("{0} stopped", name));
}
public int CompareTo(GameService other)
{
return other.serviceType.CompareTo(serviceType);
}
}
class GameServer : Element
{
private string serverIP;
private List<GameService> serviceList = new List<GameService>();
public GameServer(string name, string serverIP)
: base(name)
{
this.serverIP = serverIP;
}
public override void Add(Element element)
{
serviceList.Add((GameService)element);
}
public override void Remove(Element element)
{
serviceList.Remove((GameService)element);
}
public override void Display()
{
Console.WriteLine(string.Format("{0}{1}({2}){3}", new string('+', 10), name, serverIP, new string('+', 10)));
foreach (Element element in serviceList)
{
element.Display();
}
}
public override void Start()
{
serviceList.Sort();
Console.WriteLine("=============Starting the whole " + name + "=============");
for (int i = 0; i < serviceList.Count; i++ )
{
serviceList[i].Start();
}
Console.WriteLine("=============The whole " + name + " started=============");
}
public override void Stop()
{
Console.WriteLine("=============Stopping the whole " + name + "=============");
for (int i = serviceList.Count -1; i >= 0; i--)
{
serviceList[i].Stop();
}
Console.WriteLine("=============The whole " + name + " stopped=============");
}
}
class GameArea : Element
{
private List<GameServer> serverList = new List<GameServer>();
public GameArea(string name)
: base(name) { }
public override void Add(Element element)
{
serverList.Add((GameServer)element);
}
public override void Remove(Element element)
{
serverList.Remove((GameServer)element);
}
public override void Display()
{
Console.WriteLine(new string('=',20));
Console.WriteLine(" " + name);
Console.WriteLine(new string('=', 20));
foreach (Element element in serverList)
{
element.Display();
}
}
public override void Start()
{
Console.WriteLine("=============Starting the whole " + name + "=============");
foreach (Element element in serverList)
{
element.Start();
}
Console.WriteLine("=============The whole " + name + " started=============");
}
public override void Stop()
{
Console.WriteLine("=============Stopping the whole " + name + "=============");
foreach (Element element in serverList)
{
element.Stop();
}
Console.WriteLine("=============The whole " + name + " stopped=============");
}
}
}