面向对象设计下国际象棋棋子位置双向查询最优存储方案
推荐最优实现方案
直接采用你偏向的「Board维护双向字典+移除Piece类存储位置属性」的方案,这是面向对象实现棋类游戏的业内标准做法,核心优势是彻底消灭双数据源同步问题,你担心的双字典冗余完全可以忽略:32个棋子的两个字典内存占用可忽略不计,查询都是O(1)完全满足性能要求。
1. 改造Board类
- 私有存储新增
Dictionary<Piece, Spot> _pieceToSpot - 保留原有
Dictionary<Spot, Piece> _spotToPiece实现点位查棋子的需求 - 把
MovePiece、RemovePiece、PlacePiece这些修改状态的方法全部改为internal访问级别,仅允许同程序集的Piece类调用,对外暴露的公共接口只保留只读的CheckSpot、GetPiecePosition等查询方法
public class Board : IBoard { private uint _width; private uint _height; private Dictionary<Spot, Piece> _spotToPiece; private Dictionary<Piece, Spot> _pieceToSpot; public Board(uint width, uint height) { _width = width; _height = height; _spotToPiece = new Dictionary<Spot, Piece>(); _pieceToSpot = new Dictionary<Piece, Spot>(); } // 公共只读查询:给定点位查棋子 public Piece CheckSpot(Spot spot) { spot = transformSpot(spot); _spotToPiece.TryGetValue(spot, out var piece); return piece; } // 公共只读查询:给定棋子查位置 public Spot GetPiecePosition(Piece piece) { _pieceToSpot.TryGetValue(piece, out var spot); return spot; } // internal修改方法:仅同程序集可调用 internal bool RemovePiece(Piece piece) { if (_pieceToSpot.TryGetValue(piece, out var spot)) { _pieceToSpot.Remove(piece); _spotToPiece.Remove(spot); return true; } return false; } internal Spot MovePiece(Spot destination, Piece pieceToBeMoved) { RemovePiece(pieceToBeMoved); return PlacePiece(destination, pieceToBeMoved); } private Spot PlacePiece(Spot destination, Piece pieceToPlace) { var transformedDestination = transformSpot(destination); // 原有占位校验逻辑 _spotToPiece.Add(transformedDestination, pieceToPlace); _pieceToSpot.Add(pieceToPlace, transformedDestination); return transformedDestination; } private Spot transformSpot(Spot spot) { // 原有坐标转换逻辑 } }
2. 改造Piece类
- 移除自身存储的
_currentPosition字段,位置查询统一调用_board.GetPiecePosition(this) - 不需要再处理位置同步逻辑,所有状态修改都走Board的internal方法
public abstract class Piece : IPiece { protected IBoard _board; public ColorType Color { get; protected set; } public Piece(ColorType color, Spot initialPosition, IBoard board) { _board = board ?? throw new ArgumentNullException(nameof(board)); Color = color; // 初始化时调用Board的放置逻辑 ((Board)_board).PlacePiece(initialPosition, this); } public Spot CurrentPosition => _board.GetPiecePosition(this); public void Move() { // 原有移动规则计算逻辑,用CurrentPosition获取自身位置 var destination = new Spot(x,y); var occupyingPiece = _board.CheckSpot(destination); occupyingPiece?.RemovePiece(); // 调用Board的internal移动方法 ((Board)_board).MovePiece(destination, this); } public void RemovePiece() { ((Board)_board).RemovePiece(this); } }
3. 核心优势
- 彻底解决同步问题:Board是位置信息的唯一权威来源,双字典的维护逻辑全部封装在Board内部,所有修改操作都是原子性的,不可能出现数据不一致
- 访问权限安全:修改状态的方法都是internal,只要把Board和Piece放在同一个程序集,外部代码完全没法调用这些敏感方法,不需要友元就能实现权限隔离
- 符合面向对象设计:Piece依然持有自身移动规则的逻辑,符合你的设计预期,位置查询的性能开销可以忽略不计
内容的提问来源于stack exchange,提问作者Blasterdude8
相关产品推荐
相关产品推荐

