簡體   English   中英

如何在C#中使用多態而不是泛型

[英]How to use polymorphism instead of generic in C#

我有一個通用的基礎接口IGameble(例如,舉動是通用的)和類:國際象棋和井字游戲(以及更多的棋盤游戲),它們是從通用接口IGmable派生而不再是通用的。

我想設計類Agent(可能有幾種)來玩任何類型的游戲(而不是同時玩),但是問題是我不能

例如:

 interface IGame<T_move,T_matrix>
{
    T_matrix[,] game_state { get; }
    void MakeMove(Move mov);
    List<Move> ListAllMoves();
    ...// some more irrelevant code
}

class Tic_Tac_Toe : IGameble<Tuple<int,int>,int>
{
    public int turn;
    public int[,] game_state;
    public List<Tuple<int,int>> ListAllMoves()  {...}
    public void MakeMove(Tuple<int,int> mov) {...}
}
public Chess : IGameble <some other kind> //...
// so on more classes which uses other kind in the generic.

interface IAgent<Move>
{
    Move MakeMove();
}
public RandomAgent<T_Move,T_Matrix> : IAgent
{
   public IGameble<T_move> game;
   public D(IGameble game_) {game = game_} 
   public T_Move MakeMove() {//randomly select a move}
}
public UserAgent<T_Move,T_Matrix> : IAgent {get the move from the user}

問題是我希望隨機代理(或任何其他代理)的1個實例玩所有游戲(一次1個游戲),並使用通用強制我專門選擇我要使用的T_Move和T_Matrix的類型。 。

我可能全都錯了,並且沒有很好地使用泛型。

有建議使用IMovable和IBoardable代替通用。 這是正確的設計嗎? 它能解決所有問題嗎?

我在C#中仍然是設計模式的Noobie :(

如果有人可以鏈接到可以在這里對我有所幫助的某些設計模式,我也將不勝感激(如果有)。

我認為您可以只使用is關鍵字:

public D(IA<T> a_) 
{
    if (a_ is B) 
    {
        //do something
    }
    else if (a_ is C)
    {
        //do something else
    }
}  

C#中的泛型幾乎不像C ++那樣靈活,因此,正如一些評論者指出的那樣,您可能不想這樣做。 您可能需要設計一個中間接口,例如IMove ,您的算法可以使用該接口以通用方式枚舉移動。

我不知道您想要什么,但是您可以在沒有泛型的情況下做到。

樣例代碼:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main (string[] args)
        {
            var game = new TicTacToe (
                (x) => new UserAgent (x, "John"),
                (x) => new RandomAgent (x));

            game.Play ();

            Console.ReadKey ();
        }
    }

    public interface IGame
    {
        IMove[] GetAvailableMoves ();
    }

    public interface IMove
    {
        void MakeMove ();
        string Description { get; }
    }

    public interface IAgent
    {
        string Name { get; }
        IMove SelectMove ();
    }

    public delegate IAgent AgentCreator (IGame game);

    public class RandomAgent : IAgent
    {
        private readonly IGame game;
        private readonly Random random = new Random ();

        public RandomAgent (IGame game)
        {
            this.game = game;
        }

        public string Name => "Computer (random moves)";

        public IMove SelectMove ()
        {
            var availableMoves = game.GetAvailableMoves ();

            int moveIndex = random.Next (availableMoves.Length);

            return availableMoves[moveIndex];
        }
    }

    public class UserAgent : IAgent
    {
        private readonly IGame game;

        public UserAgent (IGame game, string playerName)
        {
            this.game = game;
            Name = playerName;
        }

        public string Name { get; }

        public IMove SelectMove ()
        {
            var availableMoves = game.GetAvailableMoves ();

            Console.WriteLine ("Choose your move:");

            for (int i = 0; i < availableMoves.Length; i++)
            {
                Console.WriteLine (i + " " + availableMoves[i].Description);
            }

            int selectedIndex = int.Parse (Console.ReadLine ());

            return availableMoves[selectedIndex];
        }
    }

    public class TicTacToe : IGame
    {
        enum CellState { Empty = 0, Circle, Cross }

        CellState[] board = new CellState[9]; // 3x3 board
        int currentPlayer = 0;

        private IAgent player1, player2;

        public TicTacToe (AgentCreator createPlayer1, AgentCreator createPlayer2)
        {
            player1 = createPlayer1 (this);
            player2 = createPlayer2 (this);
        }

        public void Play ()
        {
            PrintBoard ();

            while (GetAvailableMoves ().Length > 0)
            {
                IAgent agent = currentPlayer == 0 ? player1 : player2;

                Console.WriteLine ($"{agent.Name} is doing a move...");

                var move = agent.SelectMove ();

                Console.WriteLine ("Selected move: " + move.Description);

                move.MakeMove (); // apply move

                PrintBoard ();

                if (IsGameOver ()) break;

                currentPlayer = currentPlayer == 0 ? 1 : 0;
            }
            Console.Write ("Game over. Winner is = ..."); // some logic to determine winner
        }

        public bool IsGameOver ()
        {
            return false;
        }

        public IMove[] GetAvailableMoves ()
        {
            var result = new List<IMove> ();

            for (int i = 0; i < 9; i++)
            {
                var cell = board[i];

                if (cell != CellState.Empty) continue;

                int index = i;

                int xpos = (i % 3) + 1;
                int ypos = (i / 3) + 1;

                var move = new Move ($"Set {CurrentPlayerSign} on ({xpos},{ypos})", () => 
                {
                    board[index] = currentPlayer == 0 ? CellState.Cross : CellState.Circle;
                });

                result.Add (move);
            }

            return result.ToArray ();
        }

        private char CurrentPlayerSign => currentPlayer == 0 ? 'X' : 'O';

        public void PrintBoard ()
        {
            Console.WriteLine ("Current board state:");

            var b = board.Select (x => x == CellState.Empty ? "." : x == CellState.Cross ? "X" : "O").ToArray ();

            Console.WriteLine ($"{b[0]}{b[1]}{b[2]}\r\n{b[3]}{b[4]}{b[5]}\r\n{b[6]}{b[7]}{b[8]}");
        }
    }

    public class Move : IMove // Generic move, you can also create more specified moves like ChessMove, TicTacToeMove etc. if required
    {
        private readonly Action moveLogic;

        public Move (string moveDescription, Action moveLogic)
        {
            this.moveLogic = moveLogic;
            Description = moveDescription;
        }

        public string Description { get; }

        public void MakeMove () => moveLogic.Invoke ();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM