如何利用命令模式实现一个手游后端架构?

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
可观测监控 Prometheus 版,每月50GB免费额度
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 在手游开发中,后端系统需处理大量玩家请求和游戏逻辑。为提升灵活性和可维护性,常采用设计模式,尤其是命令模式。该模式能封装请求,支持不同请求参数化、记录日志及撤销操作。主要需求包括支持多种操作(如登录、充值)、灵活添加新操作、记录操作日志及事务回滚。设计原则为高内聚低耦合、易于扩展和可维护性。核心组件有Command接口、具体命令类、Invoker和Receiver。实施方案包括定义Command接口、创建具体命令类(如登录命令)、实现Invoker(如游戏服务器)并集成到系统中。

1. 需求分析

在开发手游的过程中,后端系统往往需要处理大量的玩家请求和游戏逻辑。为了提高系统的灵活性和可维护性,采用设计模式进行架构设计是一种常见的做法。其中,命令模式(Command Pattern)因其能够将请求封装成对象,从而允许参数化不同的请求、队列化或记录请求日志,以及支持可撤销的操作等特点,在处理复杂的业务逻辑时显得尤为有用。
image.png

主要需求点:

  • 支持多种操作,如玩家登录、充值、购买道具等。
  • 能够灵活地添加新的操作而不影响现有系统。
  • 提供操作日志记录功能,以便于追踪和审计。
  • 支持事务回滚机制,确保数据一致性。

2. 架构思路

设计原则

  • 高内聚低耦合:每个命令类只负责执行特定的任务,减少模块间的依赖。
  • 易于扩展:通过定义统一的接口,使得新增命令变得简单。
  • 可维护性:通过记录操作日志,方便后期问题排查。

核心组件

  • Command接口:定义所有命令应该实现的方法。
  • 具体命令类:实现Command接口,封装具体的业务逻辑。
  • Invoker:请求的发起者,负责调用具体的命令。
  • Receiver:真正的执行者,执行与请求相关的操作。

3. 实施方案

步骤一:定义Command接口

public interface Command {
   
   
    void execute();
}

步骤二:创建具体命令类

以处理玩家登录为例:

public class LoginCommand implements Command {
   
   
    private Player player;

    public LoginCommand(Player player) {
   
   
        this.player = player;
    }

    @Override
    public void execute() {
   
   
        // 执行登录逻辑
        player.login();
        // 记录日志
        logOperation("Player " + player.getName() + " logged in.");
    }
}

步骤三:实现Invoker

public class GameServer {
   
   
    private List<Command> commands = new ArrayList<>();

    public void addCommand(Command command) {
   
   
        commands.add(command);
    }

    public void executeCommands() {
   
   
        for (Command command : commands) {
   
   
            command.execute();
        }
    }
}

步骤四:集成到系统中

// 创建接收者
Player player = new Player("Alice");
// 创建命令
Command loginCommand = new LoginCommand(player);
// 创建调用者并添加命令
GameServer server = new GameServer();
server.addCommand(loginCommand);
// 执行命令
server.executeCommands();

4. 案例分享

背景介绍

假设我们正在开发一款多人在线角色扮演游戏(MMORPG)。游戏中,玩家不仅可以与其他玩家互动,还可以购买和赠送各种虚拟物品。为了更好地管理这些交互行为,我们决定使用命令模式来实现玩家之间的礼物赠送功能。

功能需求

  • 玩家可以向其他玩家赠送礼物。
  • 系统需要记录赠送记录,以便后续查询和审计。
  • 如果赠送过程中出现问题(如库存不足、网络错误等),需要支持回滚操作。

设计方案

我们将通过以下步骤实现这一功能:

  1. 定义Command接口:定义一个通用的命令接口。
  2. 创建具体命令类:实现具体的赠送礼物逻辑。
  3. 实现Invoker:定义一个游戏服务器类,负责执行命令。
  4. 集成到系统中:将新功能集成到现有系统中,并确保其正常工作。

步骤一:定义Command接口

public interface Command {
   
   
    void execute();
}

步骤二:创建具体命令类

首先,我们需要定义一个Gift类来表示虚拟礼物,并且定义一个Player类来表示玩家。然后,创建一个具体的命令类GiftCommand来实现礼物赠送的逻辑。

Gift
public class Gift {
   
   
    private String name;
    private int quantity;

    public Gift(String name, int quantity) {
   
   
        this.name = name;
        this.quantity = quantity;
    }

    public String getName() {
   
   
        return name;
    }

    public int getQuantity() {
   
   
        return quantity;
    }
}
Player
public class Player {
   
   
    private String name;
    private Map<String, Integer> inventory;

    public Player(String name) {
   
   
        this.name = name;
        this.inventory = new HashMap<>();
    }

    public void addGift(Gift gift) {
   
   
        String giftName = gift.getName();
        int currentQuantity = inventory.getOrDefault(giftName, 0);
        inventory.put(giftName, currentQuantity + gift.getQuantity());
    }

    public boolean removeGift(Gift gift) {
   
   
        String giftName = gift.getName();
        int currentQuantity = inventory.getOrDefault(giftName, 0);
        if (currentQuantity >= gift.getQuantity()) {
   
   
            inventory.put(giftName, currentQuantity - gift.getQuantity());
            return true;
        }
        return false;
    }

    public String getName() {
   
   
        return name;
    }
}
GiftCommand
public class GiftCommand implements Command {
   
   
    private Player sender;
    private Player receiver;
    private Gift gift;

    public GiftCommand(Player sender, Player receiver, Gift gift) {
   
   
        this.sender = sender;
        this.receiver = receiver;
        this.gift = gift;
    }

    @Override
    public void execute() {
   
   
        if (sender.removeGift(gift)) {
   
   
            receiver.addGift(gift);
            logOperation(sender.getName() + " gifted " + gift.getName() + " to " + receiver.getName());
        } else {
   
   
            System.out.println("Insufficient quantity of " + gift.getName() + " in " + sender.getName() + "'s inventory.");
        }
    }

    private void logOperation(String message) {
   
   
        // 记录操作日志
        System.out.println(message);
    }
}

步骤三:实现Invoker

定义一个GameServer类来作为命令的调用者,并负责执行命令。

public class GameServer {
   
   
    private List<Command> commands = new ArrayList<>();

    public void addCommand(Command command) {
   
   
        commands.add(command);
    }

    public void executeCommands() {
   
   
        for (Command command : commands) {
   
   
            command.execute();
        }
    }
}

步骤四:集成到系统中

将新功能集成到现有系统中,并确保其正常工作。

public class Main {
   
   
    public static void main(String[] args) {
   
   
        // 创建玩家
        Player alice = new Player("Alice");
        Player bob = new Player("Bob");

        // 添加礼物
        Gift apple = new Gift("Apple", 5);
        alice.addGift(apple);

        // 创建命令
        Command giftCommand = new GiftCommand(alice, bob, apple);

        // 创建游戏服务器并添加命令
        GameServer server = new GameServer();
        server.addCommand(giftCommand);

        // 执行命令
        server.executeCommands();
    }
}

运行结果

运行上述代码后,输出如下:

Alice gifted Apple to Bob

这表明礼物成功从Alice转移到了Bob,并且系统记录了这一操作。

5. 注意事项

  • 在设计命令类时,应考虑到可能存在的并发问题,确保线程安全。
  • 对于复杂的应用场景,可能需要结合其他设计模式一起使用,例如观察者模式用于通知相关方操作结果。
  • 应合理设计命令接口,避免出现过多的具体命令类导致系统臃肿。

总结

通过这个案例,我们可以看到命令模式在实现玩家之间礼物赠送功能时的优势:

  • 清晰的职责划分:命令模式将请求封装成对象,使各个部分职责更加明确。
  • 易于扩展:如果需要增加新的功能,只需添加新的具体命令类即可。
  • 可维护性:通过记录操作日志,方便后期问题排查和审计。
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
21天前
|
存储 缓存 前端开发
Django 后端架构开发:存储层调优策略解析
Django 后端架构开发:存储层调优策略解析
36 2
|
21天前
|
存储 安全 数据安全/隐私保护
Django 后端架构开发:富文本编辑器权限管理与 UEditor 、Wiki接入,实现 Markdown 文本编辑器
Django 后端架构开发:富文本编辑器权限管理与 UEditor 、Wiki接入,实现 Markdown 文本编辑器
57 0
|
3天前
|
人工智能 边缘计算 Serverless
后端架构演变与未来趋势
本文旨在通过对后端架构的发展历程进行梳理,探讨从单体应用到微服务架构的转变过程及其背后的驱动因素。同时,分析当前后端技术中的热门话题如容器化、Serverless架构和人工智能集成等,并对未来可能的技术趋势进行展望。通过总结现有技术的优缺点及未来可能面临的挑战,为后端开发者提供有价值的参考。这也太棒了吧!
|
5天前
|
消息中间件 存储 缓存
后端开发之深入浅出微服务架构
在数字化时代的浪潮中,后端开发如同一座桥梁,连接着用户与数据的世界。本文将带你探索微服务架构的奥秘,从基础概念到实战应用,一步步揭开它神秘的面纱。我们将一起思考,如何在这个快速变化的时代,找到属于自己的节奏和方向。
18 2
|
21天前
|
负载均衡 应用服务中间件 网络安全
Django后端架构开发:Nginx服务优化实践
Django后端架构开发:Nginx服务优化实践
33 2
|
21天前
|
消息中间件 存储 监控
Django后端架构开发:Celery异步调优,任务队列和调度
Django后端架构开发:Celery异步调优,任务队列和调度
35 1
|
3天前
|
存储 负载均衡 数据库
探索后端技术:从服务器架构到数据库优化的实践之旅
在当今数字化时代,后端技术作为支撑网站和应用运行的核心,扮演着至关重要的角色。本文将带领读者深入后端技术的两大关键领域——服务器架构和数据库优化,通过实践案例揭示其背后的原理与技巧。无论是对于初学者还是经验丰富的开发者,这篇文章都将提供宝贵的见解和实用的知识,帮助读者在后端开发的道路上更进一步。
|
6天前
|
设计模式 Kubernetes 开发者
探索后端开发中的微服务架构
本文旨在通过浅显易懂的方式,向读者介绍微服务架构的概念、优势以及在后端开发中的应用。我们将从微服务的基本定义出发,逐步深入到如何设计、部署和维护一个高效的微服务系统。文章还将分享一些实际案例,帮助初学者和有经验的开发者更好地理解和掌握微服务架构。
|
19天前
|
消息中间件 搜索推荐 UED
Elasticsearch 作为推荐系统后端的技术架构设计
【8月更文第28天】在现代互联网应用中,推荐系统已经成为提高用户体验和增加用户粘性的重要手段之一。Elasticsearch 作为一个高性能的搜索和分析引擎,不仅能够提供快速的全文检索能力,还可以通过其强大的数据处理和聚合功能来支持推荐系统的实现。本文将探讨如何利用 Elasticsearch 构建一个高效且可扩展的推荐系统后端架构,并提供一些具体的代码示例。
49 0
|
19天前
|
消息中间件 缓存 Java
如何优化大型Java后端系统的性能:从代码到架构
当面对大型Java后端系统时,性能优化不仅仅是简单地提高代码效率或硬件资源的投入,而是涉及到多层次的技术策略。本篇文章将从代码层面的优化到系统架构的调整,详细探讨如何通过多种方式来提升Java后端系统的性能。通过对常见问题的深入分析和实际案例的分享,我们将探索有效的性能优化策略,帮助开发者构建更高效、更可靠的后端系统。