You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExpressJS中改造单例Player类以实现两个独立实例的技术问题

石头剪刀布游戏:玩家分数独立统计的修复方案

问题根源

你的Player类实现了单例模式,通过静态instance属性和getInstance()方法确保整个应用中只有一个Player实例。这导致initPlayers中间件里的player1和player2指向同一个对象,所以任意一方调用addPoint()时,两个"玩家"的分数都会同步增加。

修复步骤

1. 移除Player类的单例实现

单例模式是问题核心,我们需要让每次创建Player都生成独立实例,删掉所有单例相关的静态属性和方法:

export class Player {
  private _score: number; // 改为私有属性,通过getter访问
  constructor() {
    this._score = 0;
  }

  addPoint() {
    this._score += 1;
  }

  // 添加score的getter,供外部读取分数
  get score() {
    return this._score;
  }
}

2. 修改initPlayers中间件,创建独立实例

不再使用getInstance(),直接通过new Player()生成两个独立的玩家对象:

export const initPlayers = (req: Request, _: Response, next: NextFunction) => {
  req.body = {
    ...req.body,
    player1: new Player(),
    player2: new Player(),
  };
  next();
};

3. 修复Game类的ruleSet引用问题

原Game类构造函数未接收ruleSet参数,且方法内直接引用全局变量,修改为实例属性:

export class Game {
  ruleSet: IRuleSet[];
  player1: Player;
  player2: Player;

  // 构造函数添加ruleSet参数
  constructor(player1: Player, player2: Player, ruleSet: IRuleSet[]) {
    this.player1 = player1;
    this.player2 = player2;
    this.ruleSet = ruleSet;
  }

  whoWins(player1Choice: string, player2Choice: string): { message: string } {
    console.log(player1Choice, player2Choice);
    // 遍历实例的ruleSet属性,而非全局变量
    for (const [_, rule] of this.ruleSet.entries()) {
      if (player1Choice === rule.choice) {
        if (rule.losesTo.includes(player2Choice)) {
          this.player2.addPoint();
          return {
            message: `Player 2 Wins with ${player2Choice}`,
          };
        } else if (rule.beats.includes(player2Choice)) {
          this.player1.addPoint();
          return {
            message: `Player 1 Wins with ${player1Choice}`,
          };
        } else {
          return {
            message: 'Draw',
          };
        }
      }
    }

    return {
      message: 'Invalid Choice',
    };
  }
}

4. 修复Controller的Game实例初始化

创建Game时传入ruleSet参数,确保逻辑正常运行:

// 引入你定义好的ruleSet常量
import { ruleSet } from './path-to-your-ruleSet';

public play(req: Request, res: Response) {
  const { player1Move, player2Move, player1, player2 } = req.body;
  // 传入ruleSet参数
  const game = new Game(player1, player2, ruleSet);
  const result = game.whoWins(player1Move, player2Move);

  console.log('SCORES', player1.score, player2.score); 
  res.render('game', {
    data: req.body,
    player1Score: player1.score,
    player2Score: player2.score,
  });
}

验证效果

修改后,player1和player2将是完全独立的Player实例,调用addPoint()时只会修改对应玩家的分数,双方得分将被独立统计。

内容的提问来源于stack exchange,提问作者Exodus Reed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 13:25:50