简体   繁体   English

重构C#国际象棋游戏以遵循MVC设计模式

[英]Refactor C# chess game to follow MVC design pattern

I've been given a university assignment whereby I have to develop a chess game in C# WinForms and it has been recommended that we follow the Model-View-Controller design pattern. 我接到大学的任务,要用C#WinForms开发国际象棋游戏,建议我们遵循“模型-视图-控制器”设计模式。 I'm struggling to identify what code should go where, so I'm hoping for a bit of advice and a general critique of my design. 我正在努力确定应该在哪里放置什么代码,因此我希望对我的设计有一些建议和一般性的批评。 For those brave enough to attempt traversing my spaghetti code, here's the full project . 对于那些勇于尝试遍历我的意大利面条代码的人, 这里是完整的项目 For everyone else, here's a description of what I've come up with so far: 对于其他所有人,以下是到目前为止我所提出的描述:

Model layer: 模型层:

  • Piece - Represents a single chess piece. Piece -代表一个棋子。 Has derived classes King , Queen , Rook , etc. that override virtual methods to define movement behaviour for each piece type. 具有派生类KingQueenRook等,这些类重写虚拟方法来定义每种棋子类型的移动行为。
  • Player - A small utility class that doesn't do much besides storing each player's pieces in a List<Piece> object and performing global operations on them that a single piece can't (or shouldn't) perform on its own, such as testing for check, clearing en passant and castle moves, etc. Player -一种小型实用程序类,除了将每个播放器的片段存储在List<Piece>对象中并对其执行全局操作之外,其他操作不起作用,例如,单个片段不能(或不应该)自己执行测试检查,清除过路和城堡移动等。

View layer: 视图层:

  • frmChess - The main form of the application. frmChess应用程序的主要形式。 Overrides WndProc to keep the form's 1:1 aspect ratio when the user resizes it, but is otherwise just a normal form. 重写WndProc以在用户调整其大小时保持该窗体的1:1纵横比,但否则只是普通窗体。
  • Board - A simple derivation of a standard WinForms TableLayoutPanel that I've edited in the Visual Studio designer to have 8 columns and rows. Board -我在Visual Studio设计器中编辑的标准WinForms TableLayoutPanel简单派生,它具有8列和行。 A single instance of this class sits on the main form and really doesn't do anything besides simplifying the alignment and presentation of the squares. 这个类的单个实例位于主窗体上,真的没有做任何事情 ,除了简化平方的比对和介绍。

Controller layer: 控制器层:

  • Game - A static class that stores the 64 Square s (see below) in a List<Square> object, and has various methods that allow getting the square at a given (x, y) coordinate, saving/loading the game state to/from a binary file and detecting checkmate. Game一个静态类,将64个Square (请参见下文)存储在List<Square>对象中,并具有多种方法,这些方法允许在给定的(x,y)坐标上获取平方值,将游戏状态保存/加载到/从二进制文件并检测将死。

Unsure : 不确定

  • Square - Another simple derivation of a standard WinForms control, namely Panel . Square -一个标准的WinForms控制,即另一个简单的推导Panel 64 of these have been added to the Board at design time and each one is either empty, or holds a single Piece instance at any given time. 其中的64个在设计时已添加到开发Board中,每个都为空,或在任何给定时间仅包含一个Piece实例。 That piece also holds a circular reference to its square, which I'd like to change since it seems like squares belong in the view layer, and the model should know nothing of the view. 那块还拥有对其正方形的圆形引用,由于正方形似乎属于视图层,因此我想对其进行更改,并且模型对视图一无所知。 I've also overriden the square's OnPaint method to draw its contained piece's image on its foreground, and have an event handler in the main form hooked up to every square's Click event so that pieces can be selected and moved. 我还重写了正方形的OnPaint方法,以在其前景上绘制其包含的块的图像,并在主窗体中将事件处理程序与每个正方形的Click事件挂钩,以便可以选择和移动块。 I can think of lots of other things to do from here as well, such as determining other squares that can be attacked from, or are attacking, this square. 我还可以从这里想到许多其他事情,例如确定可以从该正方形攻击或正在攻击该正方形的其他正方形。 So that makes me think that maybe it should be part of the model after all...any thoughts? 因此,这让我认为也许毕竟它应该是模型的一部分……有什么想法吗?

  • PieceMove - This class handles the doing and undoing of moves when testing for check, and also allows testing whether a move will cause check for the moving piece's team, making that move invalid. PieceMove此类在测试检查时处理动作的执行和撤消操作,并且还允许测试移动是否会引起对移动部件团队的检查,从而使该动作无效。 I really don't know whether this should be considered as part of the model, or a move controller. 我真的不知道是否应该将其视为模型或移动控制器的一部分。 Also on that note, should I have a separate move controller, view controller, etc. or just one controller class that does all of that? 还要注意的是,我应该有一个单独的移动控制器,视图控制器等,还是只有一个控制器类可以完成所有这些工作?

Lastly, I know this post is getting way too long so I apologise for that, but I'd like to implement an event-driven method of notifying the view of the model's changes, eg select a piece, move a piece, team is in check, team is in checkmate, etc. How would I go about that? 最后,我知道这篇文章太长了,为此我深表歉意,但是我想实现一种事件驱动的方法来通知模型更改的视图,例如选择一块,移动一块,团队在检查,团队处于死战状态,等等。我该怎么做?

Thank you all in advance for taking the time to read this and/or my code; 预先感谢大家花时间阅读本和/或我的代码; I really appreciate it! 我真的很感激! :D :D

I think you're off to a good start there, with all the core concepts clearly defined. 我认为您已经在这里有了一个良好的开端,所有核心概念都已明确定义。

I'd break the model down slightly differently: 我将模型分解的方式略有不同:

Model 模型

  • Board - Contains the current state of pieces on the board. 木板 -包含木板上棋子的当前状态。
    • Properties: [List<PieceState> Pieces] 属性: [List<PieceState> Pieces]
    • Methods: void PlacePiece(Piece, Square) , void MovePiece(FromSquare, ToSquare) , void RemovePiece(Square) 方法: void PlacePiece(Piece, Square)void MovePiece(FromSquare, ToSquare)void RemovePiece(Square)
  • Piece : [Type] , [Colour] [Type][Colour]
  • Square - Represents a square on the board. 正方形 -代表板上的正方形。
    • Properties: [Coordinates] 属性: [Coordinates]
  • PieceState : [Piece], [IsActive] , [Square] PieceState[Piece], [IsActive][Square]
  • MoveValidator - Ensures that a piece can perform the desired move. MoveValidator-确保棋子可以执行所需的移动。
    • Methods: bool MoveIsValid(Piece, FromSquare, ToSquare) 方法: bool MoveIsValid(Piece, FromSquare, ToSquare)
  • GameState - Describes the overall state of the game. GameState-描述游戏的整体状态。
    • Values: InPlay , CheckMate , StaleMate , etc. 值: InPlayCheckMateStaleMate等。
  • Player : Represents a player. 玩家 :代表玩家。
    • Properties: [Colour] , [List<Piece> Pieces] 属性: [Colour][List<Piece> Pieces]
  • GameLogic - Would leverage MoveValidator , as well as containing logic to ensure that pieces remain within the board boundaries, and that a square contained only one piece. GameLogic-将利用MoveValidator以及包含逻辑来确保棋子保持在棋盘边界之内,并且正方形仅包含棋子。 This class would also contain logic to determine the current GameState . 此类还将包含确定当前GameState逻辑。
    • Properties: Board 属性: Board
    • Has: MoveValidator 具有: MoveValidator
    • Methods: void SetupBoard(Board) , bool CheckMoveIsValid(Piece, FromSquare, ToSquare) , GameState GetGameState() 方法: void SetupBoard(Board)bool CheckMoveIsValid(Piece, FromSquare, ToSquare)GameState GetGameState()

View 视图

This is the part of the program that handles rendering. 这是程序中处理渲染的部分。

Think of your model as containing all the logic and state for the game, and the view layer as the logic that "paints" it on the screen. 可以将模型视为包含游戏的所有逻辑和状态,并将视图层作为将其“绘制”在屏幕上的逻辑。

In terms of any design pattern, the technical implementation is not overly important. 在任何设计模式方面,技术实施都不是很重要。 What is important is to keep things loosely coupled , and ensure that things are grouped into the right areas. 最重要的让事情变得松散耦合 ,并确保东西被分成正确的领域。

The main functions of the view are: 该视图的主要功能是:

  1. Render the board. 渲染板。
  2. Render the pieces on the board with the correct icon and colour. 使用正确的图标和颜色在板上渲染各个部分。
  3. Show relevant game statistics, score, active pieces, game time, etc. 显示相关的游戏统计数据,得分,有效棋子,游戏时间等。

Controller 控制者

The controller provides the plumbing between the model, view, and user interaction. 控制器提供了模型,视图和用户交互之间的管道。 It "glues" your classes together. 它可以将您的课程“粘合”在一起。

The controller needs to leverage and orchestrate the game classes. 控制器需要利用和协调游戏类。 The responsibilities are: 职责是:

  1. Set up a new board, then pass it back to the view for rendering. 设置一个新板,然后将其传递回视图以进行渲染。
  2. Receive user input, validate it, then update the board accordingly. 接收用户输入,对其进行验证,然后相应地更新电路板。 Pass the update view back for rendering. 返回更新视图以进行渲染。
  3. Stop play if a player wins, or a stale-mate is reached (as determined by GameState ). 如果玩家获胜或达到GameState (由GameState确定),则停止游戏。

This is far from exhaustive, but it should provide some food for thought. 这远非详尽无遗,但应该提供一些思考的空间。

Take a look here for more info on MVC structure . 在这里看看有关MVC结构的更多信息

Other patterns you may wish to look at are MVVM (model view view-model) , and MVP (model view presenter) . 您可能希望查看的其他模式是MVVM(模型视图view-model)MVP(模型视图演示者) In my opinion MVP is the best choice for a WinForms app. 我认为MVP是WinForms应用程序的最佳选择。

Lastly, there is no right way to do this! 最后,没有正确的方法可以做到这一点! Follow good design practice (but don't be dogmatic about it), keep things loosely coupled , and you should end up with spaghetti-free code . 遵循良好的设计规范(但不要固执己见 ), 使事物保持松散耦合 ,并且最终应使用不含意大利面条的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM