Welcome

首页 / 软件开发 / C# / 无废话C#设计模式之二十一:Visitor

无废话C#设计模式之二十一:Visitor2010-01-13 博客园 lovecherry意图

实现通过统一的接口访问不同类型元素的操作,并且通过这个接口可以增加新的操作而不改变元素的类。

场景

想不出什么好例子,我们在组合模式的那个例子上进行修改吧。我们知道,无论是游戏大区、游戏服务器还是游戏的服务都是一个元素,只不过它们的层次不一样。对于这样的层次结构,我们使用了组合模式来统一各层的接口,这样对游戏大区的操作和对游戏服务器的操作对调用方来说没有什么两样。在现实中,组合模式的运用往往没有这么顺利:

l 如果元素需要增加新的操作,那么势必需要在抽象元素中增加接口,这个时候的改动就非常大了,几乎每一个具体元素都需要修改。

l 如果元素并没有统一的接口,并且树枝角色中有多种树叶角色,那么树枝角色势必需要根据树叶类型来调用不同的方法。

l 如果树叶角色的接口经常发生变动,那么一旦发生变动操作树叶的树枝角色也需要发生修改。

访问者模式可以解决这些问题。

示例代码

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)

{

//A9

gameService.StartGameService(this);

}

public void Visit(GameServer gameServer)

{

//A6

gameServer.StartGameServer(this);

}

public void Visit(GameArea gameArea)

{

//A3

gameArea.StartGameArea(this);

}

}

class StopGameVisitor : IVisitor, IGameServiceVisitor, IGameServerVisitor, IGameAreaVisitor

{

public void Visit(GameService gameService)

{

//B7

Console.WriteLine(string.Format("{0} stopped", gameService.Name));

}

public void Visit(GameServer gameServer)

{

//B5

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=============");

}

public void Visit(GameArea gameArea)

{

//B3

Console.WriteLine("=============Stopping the whole " + gameArea.Name + "=============");

foreach (GameServer element in gameArea.ServerList)

{

element.Accept(this);

}

Console.WriteLine("=============The whole " + gameArea.Name + " stopped=============");

}

}

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)

{

//A8,B6

IGameServiceVisitor gameServiceVisitor = visitor as IGameServiceVisitor;

if (gameServiceVisitor != null ) gameServiceVisitor.Visit(this);

}

public int CompareTo(GameService other)

{

return other.serviceType.CompareTo(serviceType);

}

public void StartGameService(IVisitor visitor)

{

//A10

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)

{

//A5,B5

IGameServerVisitor gameServerVisitor = visitor as IGameServerVisitor;

if (gameServerVisitor != null ) gameServerVisitor.Visit(this);

}

public IEnumerator<GameService> GetEnumerator()

{

foreach (GameService gameService in serviceList)

yield return gameService;

}

public void StartGameServer(IVisitor visitor)

{

//A7

IGameServerVisitor gameServerVisitor = visitor as IGameServerVisitor;

if (gameServerVisitor != null )

{

serviceList.Sort();

Console.WriteLine("=============Starting the whole " + name + "=============");

foreach (Element gameService in serviceList)

{

gameService.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)

{

//A2,B2

IGameAreaVisitor gameAreaVisitor = visitor as IGameAreaVisitor;

if (gameAreaVisitor != null ) gameAreaVisitor.Visit(this);

}

public IEnumerator<GameServer> GetEnumerator()

{

foreach (GameServer gameServer in serverList)

yield return gameServer;

}

public void StartGameArea(IVisitor visitor)

{

//A4

IGameAreaVisitor gameAreaVisitor = visitor as IGameAreaVisitor;

if (gameAreaVisitor != null )

{

Console.WriteLine("=============Starting the whole " + name + "=============");

foreach (Element gameServer in serverList)

{

gameServer.Accept(visitor);

}

Console.WriteLine("=============The whole " + name + " started=============");

}

}

}

}