首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 設計模式無廢話系列二十一:訪問者模式(一)—— 意圖、場景與完整實作

     編輯:關於C語言

意圖

實現透過統一介面訪問不同類型元素的操作,並可在此介面增加新操作而不修改元素類別。

場景動機

承接組合模式範例(遊戲大區、伺服器、服務的樹狀結構)。組合模式統一各層介面,但現實常遇阻礙:

  • 新增操作需修改抽象元素介面,幾乎所有具體元素都要改。
  • 元素缺乏統一介面,樹枝節點含多種樹葉類型時,必須按類型分派呼叫。
  • 樹葉介面常變動,導致操作樹葉的樹枝節點跟著修改。

訪問者模式可解決上述問題。

完整範例程式碼

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=============");
            }
        }
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved