基于Spring框架怎么构建游戏玩法服务
说明:本篇阐述的问题,是基于前面的游戏服务器架构设计的。
问题
众所周知,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框架怎么构建游戏玩法服务的更多相关文章
- 基于Spring框架应用的权限控制系统的研究和实现
摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持.Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架.本文探讨了Acegi安全 ...
- 简单Elixir游戏服设计- 游戏玩法介绍
抄以前的,做了点修改. 到目前为止,我们完成了玩家的数据和进程建模,现在介绍游戏玩法. 为什么我们还不做客户端接入.协议指定呢?为什么还没有网关和数据存储呢.在我接手的游戏, 这些通常已经定下来了,我 ...
- 基于Spring框架的简单多数据源切换解决办法
基于Spring框架的简单多数据源切换解决办法 Spring框架JDBC包提供了一个抽象类AbstractRoutingDataSource提供了动态切换数据库的基础方法.我们仅仅需要实现一个简单的数 ...
- 第一次玩博客,今天被安利了一个很方便JDBC的基于Spring框架的一个叫SimpleInsert的类,现在就来简单介绍一下
首先先对这段代码的简单介绍,我之前在需要操作JDBC的时候总是会因为经常要重新写SQL语句感到很麻烦.所以就能拿则拿不能拿的就简单地封装了一下. 首先是Insert.Spring框架的JDBC包里面的 ...
- 基于Spring Boot+Cloud构建微云架构
前言 首先,最想说的是,当你要学习一套最新的技术时,官网的英文文档是学习的最佳渠道.因为网上流传的多数资料是官网翻译而来,很多描述的重点也都偏向于作者自身碰到的问题,这样就很容易让你理解和操作出现偏差 ...
- 轻量级高性能ORM框架:Dapper高级玩法
Dapper高级玩法1: 数据库中带下划线的表字段自动匹配无下划线的Model字段. Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 备 ...
- 使用 Spring Cloud Stream 构建消息驱动微服务
相关源码: spring cloud demo 微服务的目的: 松耦合 事件驱动的优势:高度解耦 Spring Cloud Stream 的几个概念 Spring Cloud Stream is a ...
- 基于spring框架的apache shiro简单集成
关于项目的安全保护,我一直想找一个简单配置就能达到目的的方法,自从接触了shiro,这个目标总算达成了,以下结合我使用shiro的经验,谈谈比较轻便地集成该功能. 首先我们先了解一下shiro是什么. ...
- 使用NetBeans搭建基于Spring框架的Web应用
NetBeans下载链接:https://netbeans.org/. 第一步:选择“文件”菜单下的“新建项目”: 第二步:类别选择“Java Web”,项目选择“Web应用程序”,单击“下一步”: ...
随机推荐
- EntityFramework进阶(五)- 分页
本系列原创博客代码已在EntityFramework6.0.0测试通过,转载请标明出处 我们创建分页信息类CommonPagedList,包含了字段总条数,总页数,当前页码,页大小,当前页数据. us ...
- Docker学习笔记(2)--Docker常用命令
1. 查看docker信息(version.info) # 查看docker版本 $docker version # 显示docker系统的信息 $docker info 2. 对image的操作(s ...
- Linux基础命令汇总109条
1 文件管理 1.1 basename 1.1.1 功能说明 从文件名中去掉路径和扩展名 例:basename include/stdio.h .h Output &quo ...
- redis过期事件回调函数,与有序集合
https://cloud.tencent.com/developer/article/1347437 python中的Redis键空间通知(过期回调) set notify-keyspace-ev ...
- Flutter——FloatingActionButton组件(浮动按钮组件)
FloatingActionButton 简称 FAB ,可以实现浮动按钮,也可以实现类似闲鱼 app 的地步凸起导航. 属性名称 属性值 child 子视图,一般为 Icon,不推荐使用文字 ...
- Django中过滤的实现
过滤模块 安装 >: pip install django-filter 注册应用:settings/dev.py INSTALLED_APPS = [ # 列表过滤模块 'django_fil ...
- Linux学习之五-Linux系统终端常用的快捷键
Linux系统终端常用的快捷键 (使用快捷键能大大提高效率,部分用在远程登录的工具如Xshell下) 剪切板操作(终端不支持,因为终端是纯命令行) Ctrl+insert 复制 Shift+i ...
- FontLab
FontLab 字体制作软件
- java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver
SpringBoot运行报错——java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or rep ...
- Selenium常用API的使用java语言之11-设置元素等待
WebDriver提供了两种类型的等待:显式等待和隐式等待. 1.显示等待 WebDriver提供了显式等待方法,专门针对某个元素进行等待判断. import org.openqa.selenium. ...