實現透過統一介面訪問不同類型元素的操作,並可在此介面增加新操作而不修改元素類別。
承接組合模式範例(遊戲大區、伺服器、服務的樹狀結構)。組合模式統一各層介面,但現實常遇阻礙:
訪問者模式可解決上述問題。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace VisitorExample
{
class Program
{
static void Main(string[] args)
{
Element server1 = new GameServer("GS1", "192.168.0.1");
server1.Add(new GameService("Lobby1", 1, "S5Lobby1", 100));
server1.Add(new GameService("Lobby2", 1, "S5Lobby2", 200));
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("Lobby3", 1, "S5Lobby3", 150));
server2.Add(new GameService("Lobby4", 1, "S5Lobby4", 250));
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.Accept(new StartGameVisitor()); // A1
area.Accept(new StopGameVisitor()); // B1
server1.Accept(new QueryPlayerCountVisitor());
server2.Accept(new QueryPlayerCountVisitor());
area.Accept(new QueryPlayerCountVisitor());
}
}
interface IVisitor { }
interface IGameServiceVisitor { void Visit(GameService gameService); }
interface IGameServerVisitor { void Visit(GameServer gameServer); }
interface IGameAreaVisitor { void Visit(GameArea gameArea); }
class StartGameVisitor : IVisitor, IGameServiceVisitor, IGameServerVisitor, IGameAreaVisitor
{
public void Visit(GameService gameService) { gameService.StartGameService(this); } // A9
public void Visit(GameServer gameServer) { gameServer.StartGameServer(this); } // A6
public void Visit(GameArea gameArea) { gameArea.StartGameArea(this); } // A3
}
class StopGameVisitor : IVisitor, IGameServiceVisitor, IGameServerVisitor, IGameAreaVisitor
{
public void Visit(GameService gameService) { Console.WriteLine(string.Format("{0} stopped", gameService.Name)); } // B7
public void Visit(GameServer gameServer) {
Console.WriteLine("=============Stopping the whole " + gameServer.Name + "=============");
for (int i = gameServer.ServiceList.Count - 1; i >= 0; i--)
gameServer.ServiceList[i].Accept(this);
Console.WriteLine("=============The whole " + gameServer.Name + " stopped=============");
} // B5
public void Visit(GameArea gameArea) {
Console.WriteLine("=============Stopping the whole " + gameArea.Name + "=============");
foreach (GameServer element in gameArea.ServerList)
element.Accept(this);
Console.WriteLine("=============The whole " + gameArea.Name + " stopped=============");
} // B3
}
class QueryPlayerCountVisitor : IVisitor, IGameServerVisitor, IGameAreaVisitor
{
public void Visit(GameServer gameServer) {
int playerCount = 0;
foreach (GameService gameService in gameServer)
if (gameService.ServiceType == 1)
playerCount += gameService.PlayerCount;
Console.WriteLine("=============Player Count on " + gameServer.Name + " is:" + playerCount);
}
public void Visit(GameArea gameArea) {
int playerCount = 0;
foreach (GameServer gameServer in gameArea)
foreach (GameService gameService in gameServer)
if (gameService.ServiceType == 1)
playerCount += gameService.PlayerCount;
Console.WriteLine("=============Player Count on " + gameArea.Name + " is:" + playerCount);
}
}
abstract class Element
{
protected string name;
public string Name { get { return name; } }
public Element(string name) { this.name = name; }
public abstract void Add(Element element);
public abstract void Remove(Element element);
public abstract void Accept(IVisitor visitor);
}
class GameService : Element, IComparable<GameService>
{
private int serviceType;
public int ServiceType { get { return serviceType; } set { serviceType = value; } }
private string serviceName;
private int playerCount;
public int PlayerCount { get { return playerCount; } set { playerCount = value; } }
public GameService(string name, int serviceType, string serviceName) : base(name)
{ this.serviceName = serviceName; this.serviceType = serviceType; }
public GameService(string name, int serviceType, string serviceName, int playerCount) : base(name)
{ this.serviceName = serviceName; this.serviceType = serviceType; this.playerCount = playerCount; }
public override void Add(Element element) { throw new ApplicationException("xxx"); }
public override void Remove(Element element) { throw new ApplicationException("xxx"); }
public override void Accept(IVisitor visitor) {
IGameServiceVisitor v = visitor as IGameServiceVisitor;
if (v != null) v.Visit(this);
}
public int CompareTo(GameService other) { return other.serviceType.CompareTo(serviceType); }
public void StartGameService(IVisitor visitor) { Console.WriteLine(string.Format("{0} started", name)); }
}
class GameServer : Element
{
private string serverIP;
private List<GameService> serviceList = new List<GameService>();
public List<GameService> ServiceList { get { return serviceList; } }
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 Accept(IVisitor visitor) {
IGameServerVisitor v = visitor as IGameServerVisitor;
if (v != null) v.Visit(this);
}
public IEnumerator<GameService> GetEnumerator() {
foreach (GameService gs in serviceList) yield return gs;
}
public void StartGameServer(IVisitor visitor) {
IGameServerVisitor v = visitor as IGameServerVisitor;
if (v != null) {
serviceList.Sort();
Console.WriteLine("=============Starting the whole " + name + "=============");
foreach (Element gs in serviceList) gs.Accept(visitor);
Console.WriteLine("=============The whole " + name + " started=============");
}
}
}
class GameArea : Element
{
private List<GameServer> serverList = new List<GameServer>();
public List<GameServer> ServerList { get { return serverList; } }
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 Accept(IVisitor visitor) {
IGameAreaVisitor v = visitor as IGameAreaVisitor;
if (v != null) v.Visit(this);
}
public IEnumerator<GameServer> GetEnumerator() {
foreach (GameServer gs in serverList) yield return gs;
}
public void StartGameArea(IVisitor visitor) {
IGameAreaVisitor v = visitor as IGameAreaVisitor;
if (v != null) {
Console.WriteLine("=============Starting the whole " + name + "=============");
foreach (Element gs in serverList) gs.Accept(visitor);
Console.WriteLine("=============The whole " + name + " started=============");
}
}
}
}