说明:本篇阐述的问题,是基于前面的游戏服务器架构设计的。

问题

众所周知,Spring最擅长的领域是无状态服务的构建,而游戏(尤其是玩法部分)是有状态的。以棋牌游戏为例,玩法服务里面大概涉及以下两类对象:

1、无状态的服务,比如数据读写、通信等;

2、与游戏桌子绑定的有状态类,比如桌子本身,状态机,玩家的游戏状态等。

后者肯定是要访问前者提供的方法的,那么后者怎么拿到前者的引用呢。

我们一开始的做法是,无状态的服务做成Spring Bean,然后在启动的时候,把这些service的引用放到一个静态了类的字段里面,类似这样:

public class ServiceContainer {
public static ServiceBean1 bean1;
public static ServiceBean2 bean2;
... public static init(ApplicationContext context)
{
bean1 = context.getBean(ServiceBean1.class);
bean2 = context.getBean(ServiceBean2.class);
...
}
}

然后有状态的对象就可以简单地通过ServiceContainer.bean1来访问无状态的服务了。

不过代码多了以后,发现这种方式实在有点糟糕。 由于对ServiceContainer的访问实在太简单了,导致大家随意地在里面添加新的字段,最后对象之间的耦合依赖非常混乱,完全没有享受到使用Spring的好处。

解决办法

为了解决问题,首先确立一个原则,不允许通过静态方法、静态字段来暴露服务;单例模式当然也不允许(本质还是静态方法),既然用了Spring,就要按Spring的架构哲学来搞。

第一个办法是这样的,在创建一个有状态的对象的时候,如果这个对象需要依赖某些Service,那么在初始化的过程中手动注入进去,以游戏桌table为例,代码类似这样:

public class GameTable {
public ServiceBean1 bean1;
public ServiceBean2 bean2;
... public init(ApplicationContext context)
{
bean1 = context.getBean(ServiceBean1.class);
bean2 = context.getBean(ServiceBean2.class);
...
}
}

这个方法,虽然看起来和ServiceContainer半斤八两,但实际上要好很多,至少某个玩法的table依赖哪些服务一目了然。不过产品功能复杂性增加以后,table依赖的服务越来越多,还是会让人很不爽。

继续优化方案

table里面注入了太多的service,本质上说明游戏玩法逻辑的拆分不够细。

在前边的文章里面,我们的核心玩法逻辑拆分成table(桌子),state(状态机),messageProcessor(消息处理器),现在重新捋一下这些角色的职责:

1、table以及相关的类是游戏玩法的领域模型,专注于游戏的数据状态和基本规则算法;

2、state状态机用来简化流程控制,专注于消息的过滤,和状态的切换;

3、messageProcessor,专注于消息的处理,服务于玩法的所有桌子,也就是说它是无状态的;

4、其他业务逻辑,比如数据的存取,游戏日志处理,外围功能(比如任务)。

其中table和state都是内存对象,而messageProcessor和其他逻辑都是标准的Service Bean,state将消息过滤后,委托给messageProcessor来处理,依据处理结果来迁移状态。

一个典型的messageProcessor接口可能类似这样的:

public boolean processPlayerJoin(Table table, Player player, Message message)
{
if (玩家是否满足入桌条件)
{
table.addPlayer(player);
return true;
}
return false
}

基于Spring框架怎么构建游戏玩法服务的更多相关文章

  1. 基于Spring框架应用的权限控制系统的研究和实现

    摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持.Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架.本文探讨了Acegi安全 ...

  2. 简单Elixir游戏服设计- 游戏玩法介绍

    抄以前的,做了点修改. 到目前为止,我们完成了玩家的数据和进程建模,现在介绍游戏玩法. 为什么我们还不做客户端接入.协议指定呢?为什么还没有网关和数据存储呢.在我接手的游戏, 这些通常已经定下来了,我 ...

  3. 基于Spring框架的简单多数据源切换解决办法

    基于Spring框架的简单多数据源切换解决办法 Spring框架JDBC包提供了一个抽象类AbstractRoutingDataSource提供了动态切换数据库的基础方法.我们仅仅需要实现一个简单的数 ...

  4. 第一次玩博客,今天被安利了一个很方便JDBC的基于Spring框架的一个叫SimpleInsert的类,现在就来简单介绍一下

    首先先对这段代码的简单介绍,我之前在需要操作JDBC的时候总是会因为经常要重新写SQL语句感到很麻烦.所以就能拿则拿不能拿的就简单地封装了一下. 首先是Insert.Spring框架的JDBC包里面的 ...

  5. 基于Spring Boot+Cloud构建微云架构

    前言 首先,最想说的是,当你要学习一套最新的技术时,官网的英文文档是学习的最佳渠道.因为网上流传的多数资料是官网翻译而来,很多描述的重点也都偏向于作者自身碰到的问题,这样就很容易让你理解和操作出现偏差 ...

  6. 轻量级高性能ORM框架:Dapper高级玩法

    Dapper高级玩法1: 数据库中带下划线的表字段自动匹配无下划线的Model字段. Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 备 ...

  7. 使用 Spring Cloud Stream 构建消息驱动微服务

    相关源码: spring cloud demo 微服务的目的: 松耦合 事件驱动的优势:高度解耦 Spring Cloud Stream 的几个概念 Spring Cloud Stream is a ...

  8. 基于spring框架的apache shiro简单集成

    关于项目的安全保护,我一直想找一个简单配置就能达到目的的方法,自从接触了shiro,这个目标总算达成了,以下结合我使用shiro的经验,谈谈比较轻便地集成该功能. 首先我们先了解一下shiro是什么. ...

  9. 使用NetBeans搭建基于Spring框架的Web应用

    NetBeans下载链接:https://netbeans.org/. 第一步:选择“文件”菜单下的“新建项目”: 第二步:类别选择“Java Web”,项目选择“Web应用程序”,单击“下一步”: ...

随机推荐

  1. js入门之内置对象Math

    一. 复习数据类型 简单数据类型, 基本数据类型/值类型 Number String Boolean Null Undefined 复杂数据类型 引用类型 Object 数组 数据在内存中是如何存储的 ...

  2. How to delete SAP* from HANA Tenant database

    How to delete SAP* from HANA Tenant database 1.如何登录HANA的多租户(TDC)数据库 使用SAPS4端对应的SAP账户,比如S4D的账户为s4dadm ...

  3. linux后台执行命令crontab

    有如下几种方式: crontab at & nohup 1. crontab 定时执行任务 # crontab -e //编辑crontab配置文件 Select an editor. To ...

  4. WinServer-SMTP服务

    摘要 SMTP服务是用来发送邮件的,常用于代码中发送邮件,不能接收.本章介绍SMTP服务的安装,配置. 搭建F5负载均衡集群注意事项: 1.集群不能与exchang在同网段,否则发不出邮件. 2.AP ...

  5. centos8 安装 mongodb 4.2 (使用yum)

    1.制作 repo 文件 参考 mongodb 官方的安装文档,使用下面的脚本制作Yum库安装mongodb4.2,但安装过程提示 "Failed to synchronize cache ...

  6. Three.js入门详解

    什么是WebGL   WebGL(Web 图形库)是一种 JavaScript API,用于在任何兼容的 Web 浏览器中呈现交互式 3D 和 2D 图形,而无需使用插件.WebGL 通过引入一个与 ...

  7. certbot更新错误

    自动更新老是提示这个错误. root@vultr:~/certbot# ./certbot-auto Upgrading certbot-auto 0.29.1 to 0.34.2... Couldn ...

  8. Java7--try - with - resources

    从 Java 7 build 105 版本开始,Java 7 的编译器和运行环境支持新的 try-with-resources 语句,称为 ARM 块(Automatic Resource Manag ...

  9. 多线程下,使用new实现单例

    import threading class Test(object): from threading import Lock lock = Lock() flag = None def __new_ ...

  10. 关于创建Django表单Forms继承BaseForm的问题

    在创建Django表单时,因为需要验证用户输入的验证码是否正确,因此需要在session里提取当前验证码的值和POST提交过来的值进行比对,如图: form.py from django import ...