將物件組合成樹形結構以表示「部分-整體」層次,使 Client 對單一物件與組合物件具有一致性使用方式。
多大區 → 多伺服器 → 多服務(Log、Rank、DataExchange、Gate、Lobby)。需求:顯示所有資訊,支援單一服務/整台伺服器/整個大區的啟動與停止。
若 Client 直接依賴具體層級,總裁級管理者將需與底層員工直接溝通。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 // Component
{
protected string _name;
public Element(string name) { _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> // Leaf
{
private int _serviceType;
private string _serviceName;
public GameService(string name, int serviceType, string serviceName) : base(name)
{ _serviceName = serviceName; _serviceType = serviceType; }
public override void Add(Element e) => throw new ApplicationException("Leaf cannot add");
public override void Remove(Element e) => throw new ApplicationException("Leaf cannot remove");
public override void Display() => Console.WriteLine($"name:{_name},serviceType:{_serviceType},serviceName:{_serviceName}");
public override void Start() => Console.WriteLine($"{_name} started");
public override void Stop() => Console.WriteLine($"{_name} stopped");
public int CompareTo(GameService other) => other._serviceType.CompareTo(_serviceType);
}
class GameServer : Element // Composite
{
private string _serverIP;
private List<GameService> _services = new List<GameService>();
public GameServer(string name, string serverIP) : base(name) { _serverIP = serverIP; }
public override void Add(Element e) => _services.Add((GameService)e);
public override void Remove(Element e) => _services.Remove((GameService)e);
public override void Display()
{
Console.WriteLine(new string('+', 10) + _name + "(" + _serverIP + ")" + new string('+', 10));
foreach (var e in _services) e.Display();
}
public override void Start()
{
_services.Sort();
Console.WriteLine("=============Starting " + _name + "=============");
foreach (var s in _services) s.Start();
Console.WriteLine("=============" + _name + " started=============");
}
public override void Stop()
{
Console.WriteLine("=============Stopping " + _name + "=============");
for (int i = _services.Count - 1; i >= 0; i--) _services[i].Stop();
Console.WriteLine("=============" + _name + " stopped=============");
}
}
class GameArea : Element // Composite (Root)
{
private List<GameServer> _servers = new List<GameServer>();
public GameArea(string name) : base(name) { }
public override void Add(Element e) => _servers.Add((GameServer)e);
public override void Remove(Element e) => _servers.Remove((GameServer)e);
public override void Display()
{
Console.WriteLine(new string('=', 20));
Console.WriteLine(" " + _name);
Console.WriteLine(new string('=', 20));
foreach (var e in _servers) e.Display();
}
public override void Start()
{
Console.WriteLine("=============Starting " + _name + "=============");
foreach (var e in _servers) e.Start();
Console.WriteLine("=============" + _name + " started=============");
}
public override void Stop()
{
Console.WriteLine("=============Stopping " + _name + "=============");
foreach (var e in _servers) e.Stop();
Console.WriteLine("=============" + _name + " stopped=============");
}
}
}
IComparable<GameService> 實現服務啟動順序排序area,一鍵操作整棵樹