手游后端架构中,用命令模式解决什么问题

2024-09-05 16:44

本文主要是介绍手游后端架构中,用命令模式解决什么问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Hello,大家好,我是 V 哥。命令模式(Command Pattern)是一种行为设计模式,它将一个请求封装为一个对象,从而允许用户使用不同的请求、队列或日志请求来参数化其他对象。命令模式也支持可撤销的操作。在手游后端架构中,

  1. 命令模式可以将玩家的操作请求(如移动、攻击、技能释放等)封装成对象,这些对象可以被存储在队列中,以便按顺序处理。

  2. 通过命令模式,可以将发起操作的对象(发送者)和执行操作的对象(接收者)分离,使得系统更加模块化,易于扩展和维护。

  3. 在游戏中,玩家可能会犯错或需要撤销之前的行动。命令模式可以轻松实现操作的撤销和重做功能。

  4. 命令模式可以将操作封装为对象,这些对象可以异步执行,不会阻塞主线程,提高游戏的响应性和性能。

  5. 在游戏中,一个玩家的行为可能会影响其他玩家或游戏环境。命令模式可以将这些行为封装为命令对象,并通过事件系统广播给所有受影响的实体。

  6. 在多人游戏中,命令模式可以管理玩家之间的协同操作,确保操作的一致性和顺序性。

  7. 游戏中的资源(如金币、道具等)的分配和回收可以通过命令模式来管理,确保资源操作的原子性和一致性。

  8. 在网络游戏中,命令模式可以用于封装网络请求和响应,简化网络通信逻辑。

还有更多具体的问题可以解决,你是不是觉得命令模式原来可以这么强大呀,当然命令模式通常与其他设计模式结合使用,如策略模式、观察者模式、状态模式等,以构建一个灵活、可扩展和易于维护的系统。

接下来,上案例喽。

创建一个完整的手游后端服务端示例涉及到许多组件,包括网络通信、数据库交互、业务逻辑处理等。在这里,我将提供一个非常简化的示例,它模拟了一个基本的游戏后端服务,包括玩家注册、登录和获取玩家信息的功能。这个示例将使用Java的Socket编程来处理客户端请求。

注意:这个示例仅用于教学目的,实际的手游后端会更加复杂,需要考虑安全性、并发性、数据库存储、错误处理等多个方面。

首先,我们需要一个Player类来表示玩家:

public class Player {private String id;private String username;private String password;public Player(String id, String username, String password) {this.id = id;this.username = username;this.password = password;}// Getters and setterspublic String getId() {return id;}public String getUsername() {return username;}public String getPassword() {return password;}
}

接下来,我们创建一个PlayerService类来处理玩家相关的业务逻辑:

import java.util.HashMap;
import java.util.Map;public class PlayerService {private Map<String, Player> players = new HashMap<>();public synchronized String registerPlayer(String username, String password) {String playerId = Integer.toString(players.size() + 1);players.put(playerId, new Player(playerId, username, password));return playerId;}public synchronized Player login(String username, String password) {for (Player player : players.values()) {if (player.getUsername().equals(username) && player.getPassword().equals(password)) {return player;}}return null;}public synchronized Player getPlayer(String playerId) {return players.get(playerId);}
}

然后,我们创建一个GameServer类来处理网络连接和请求:

import java.io.*;
import java.net.*;
import java.util.Scanner;public class GameServer {private ServerSocket serverSocket;private final int PORT = 12345;private PlayerService playerService = new PlayerService();public void startServer() {try {serverSocket = new ServerSocket(PORT);System.out.println("Game server is running on port " + PORT);while (true) {Socket socket = serverSocket.accept();new Handler(socket).start();}} catch (IOException e) {e.printStackTrace();}}private class Handler extends Thread {private Socket socket;private BufferedReader in;private PrintWriter out;public Handler(Socket socket) {this.socket = socket;try {in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(), true);} catch (IOException e) {e.printStackTrace();}}public void run() {try {String inputLine;while ((inputLine = in.readLine()) != null) {System.out.println("Received: " + inputLine);if ("REGISTER".equals(inputLine)) {String playerId = playerService.registerPlayer("username", "password");out.println("REGISTERED " + playerId);} else if ("LOGIN".equals(inputLine)) {Player player = playerService.login("username", "password");if (player != null) {out.println("LOGIN_SUCCESS " + player.getId());} else {out.println("LOGIN_FAILURE");}} else if ("GET_PLAYER".equals(inputLine)) {String[] parts = inputLine.split(" ", 2);if (parts.length == 2) {Player player = playerService.getPlayer(parts[1]);if (player != null) {out.println("PLAYER " + player.getId() + " " + player.getUsername());} else {out.println("PLAYER_NOT_FOUND");}}}}} catch (IOException e) {e.printStackTrace();} finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) {GameServer server = new GameServer();server.startServer();}
}

GameServer类创建了一个服务器套接字,并监听指定的端口。每当有新的客户端连接时,它都会创建一个新的Handler线程来处理该连接。Handler线程读取客户端发送的命令,并根据命令执行相应的操作,如注册玩家、登录或获取玩家信息。

以上演示了最基本的文本协议来进行通信,客户端和服务器之间通过读取和发送字符串来交互。当然你也可以使用更加复杂的协议,比如 JSONProtocol Buffers等,看你的需求,这里是为了简化演示逻辑哈。

要运行这个示例,你需要创建一个客户端来连接到服务器并发送命令。客户端可以使用任何支持网络通信的编程语言编写。

下面是一个 Java 客户端代码示例,它将连接到服务器并发送一些命令来注册玩家、登录并获取玩家信息。这个客户端将使用 GameServer 示例中定义的相同协议。

import java.io.*;
import java.net.Socket;public class GameClient {private Socket socket;private PrintWriter out;private BufferedReader in;public GameClient(String serverAddress, int port) {try {socket = new Socket(serverAddress, port);out = new PrintWriter(socket.getOutputStream(), true);in = new BufferedReader(new InputStreamReader(socket.getInputStream()));} catch (IOException e) {e.printStackTrace();}}public void sendCommand(String command) {out.println(command);}public String readResponse() {try {return in.readLine();} catch (IOException e) {e.printStackTrace();return null;}}public void close() {try {socket.close();} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {GameClient client = new GameClient("localhost", 12345);// 注册玩家client.sendCommand("REGISTER");String registerResponse = client.readResponse();System.out.println("Register response: " + registerResponse);// 登录玩家client.sendCommand("LOGIN");String loginResponse = client.readResponse();System.out.println("Login response: " + loginResponse);// 获取玩家信息String[] loginParts = loginResponse.split(" ", 2);if (loginParts.length == 2 && "LOGIN_SUCCESS".equals(loginParts[0])) {client.sendCommand("GET_PLAYER " + loginParts[1]);String playerResponse = client.readResponse();System.out.println("Player info response: " + playerResponse);}// 关闭连接client.close();}
}

我们首先创建了一个 GameClient 实例,指定服务器的地址和端口。然后,我们使用 sendCommand 方法发送命令到服务器,并使用 readResponse 方法读取服务器的响应。

main 方法中,我们执行以下步骤:

  1. 发送 “REGISTER” 命令以注册新玩家,并读取响应。
  2. 检查注册响应是否表示成功,并提取玩家 ID。
  3. 使用 “LOGIN” 命令登录玩家,并读取响应。
  4. 检查登录响应是否表示成功,并提取玩家 ID。
  5. 使用 “GET_PLAYER” 命令和玩家 ID 获取玩家信息,并读取响应。
  6. 检查玩家信息响应,并打印玩家的 ID 和用户名。
  7. 最后,关闭与服务器的连接。

代码是这样的:

下面是 GameClient 类中 main 方法的完整测试代码,它将连接到服务器并发送一系列命令来演示注册、登录和获取玩家信息的过程:

public static void main(String[] args) {// 创建客户端实例,连接到服务器GameClient client = new GameClient("localhost", 12345);// 注册玩家client.sendCommand("REGISTER");String registerResponse = client.readResponse();System.out.println("Register response: " + registerResponse);// 假设注册成功,服务器会返回 REGISTERED 后跟玩家IDif (registerResponse.startsWith("REGISTERED")) {String playerId = registerResponse.substring("REGISTERED ".length());System.out.println("Registered player ID: " + playerId);// 登录玩家client.sendCommand("LOGIN");String loginResponse = client.readResponse();System.out.println("Login response: " + loginResponse);// 假设登录成功,服务器会返回 LOGIN_SUCCESS 后跟玩家IDif (loginResponse.startsWith("LOGIN_SUCCESS")) {String loggedInPlayerId = loginResponse.substring("LOGIN_SUCCESS ".length());System.out.println("Logged in player ID: " + loggedInPlayerId);// 获取玩家信息client.sendCommand("GET_PLAYER " + loggedInPlayerId);String playerResponse = client.readResponse();System.out.println("Player info response: " + playerResponse);// 假设获取玩家信息成功,服务器会返回 PLAYER 后跟玩家ID和用户名if (playerResponse.startsWith("PLAYER")) {String[] playerInfo = playerResponse.split(" ", 3);if (playerInfo.length == 3) {System.out.println("Player ID: " + playerInfo[1]);System.out.println("Player Username: " + playerInfo[2]);} else {System.out.println("Error: Invalid player info format.");}} else {System.out.println("Error: Failed to get player info.");}} else {System.out.println("Error: Login failed.");}} else {System.out.println("Error: Registration failed.");}// 关闭连接client.close();
}

完事儿。以上就是本文的全部内容笔记,感谢老铁们的支持和鼓励,不当之处还请不吝赐教,欢迎关注威哥爱编程,努力的人相信总会有回报。

这篇关于手游后端架构中,用命令模式解决什么问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139515

相关文章

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

关于Maven生命周期相关命令演示

《关于Maven生命周期相关命令演示》Maven的生命周期分为Clean、Default和Site三个主要阶段,每个阶段包含多个关键步骤,如清理、编译、测试、打包等,通过执行相应的Maven命令,可以... 目录1. Maven 生命周期概述1.1 Clean Lifecycle1.2 Default Li

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

解决systemctl reload nginx重启Nginx服务报错:Job for nginx.service invalid问题

《解决systemctlreloadnginx重启Nginx服务报错:Jobfornginx.serviceinvalid问题》文章描述了通过`systemctlstatusnginx.se... 目录systemctl reload nginx重启Nginx服务报错:Job for nginx.javas

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

Mysql DATETIME 毫秒坑的解决

《MysqlDATETIME毫秒坑的解决》本文主要介绍了MysqlDATETIME毫秒坑的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 今天写代码突发一个诡异的 bug,代码逻辑大概如下。1. 新增退款单记录boolean save = s