GoF解释:
让一群对象都有机会处理一个请求,并减少请求发送者与接受者之间的耦合程度。将所有的接受者对象串联起来,让请求沿着串传递,知道有一个对象可以解决请求的问题为止。
模式说明:
对于一个问题或者一项需求,我们可以制造一条流水线,流水线上每个节点都可能是解决问题的方式,或者是满足需求的一部分。GoF四人组的解释只解释了对问题的处理,而责任链模式在当前的应用很多都是处理需求的组装,熟悉Java后台开发,尤其是Netty框架,大量的应用了责任链模式对对象进行组装。我们先来了解一下这个模式,再来仔细说一下这个模式的好处
案例说明:限时的组合关卡活动
1.需求说明:策划需要出限时闯关活动,配置一组关卡的ID,然后玩家从第一关开始,一直突破到最后一关
2.代码分析:
实现IStageHandler
public abstract class IStageHandler{
protected int mStageId ;
protected IStageHandler mNextHandler;
public IStageHandler(int stageId){
this.mStageId = stageId;
}
//初始化Stage
public virtual void InitStage(){
//TODO
}
//设置本关卡的下个关卡
public virtual IStageHandler SetNextHandler(IStageHandler nextHandler){
this.mNextHandler = nextHandler
return this.mNextHandler;
}
//更新关卡行为
public virtual void UpdateStage(){
if(CheckStageOver()){
if(this.mNextHandler != null){
this.mNextHandler.UpdateStage();
return ;
}
}
//TODO
}
//检查关卡是否结束
public virtual bool CheckStageOver(){
//TODO
}
}
实现关卡控制系统
public class StageSystem{
private IStageHandler mRootStage = null;
//设置一组关卡ID,在实际中可能是运营在服务器上指定,也可能是策划在配置表中指定
private List<int> stageIds = new List<int> { 1001,2001,3001,4001,5001};
public void InitStage(){
IStageHandler stage = null;
//因为博主想让设计更贴合项目实际应用一点,所以并没有用完全显示的链式设计。这里的链式设计希望大家能理解。
for(int i=0; i<stageIds.Count-1; i++){
if( stage == null ) {
stage = new IStageHandler(stageIds[i]);
this.mRootStage = stage;
}
else {
stage = stage.SetNextHandler(new IStageHandler(stageIds[i]));
}
}
}
public void Update(){
if(this.mRootStage != null){
//从第一关开始更新,链式设计会让关卡链自动找到当前还没有完成的关卡
this.mRootStage.UpdateStage();
}
}
}
从代码中就可以看出,关卡系统不需要再维护已经到了哪一关,只需要直接更新一条关卡链的头部节点,而具体已经到了哪一关,关卡链内部会自动更新。这样我们就把发送者和请求分离开来,但是每一个节点都能接收到问题并且执行。
当然责任链不接用于问题的解决,也用于一些对象的完整设置。我们也来举一个例子,比如我们要装配一个服务器处理对象
需求:设置最大链接个数,设置链接是否一直保持活动,设置接收文本的解析类,设置回传消息文本的封装类。
ServerBootstrap: 实际处理链接和消息的封装类
public class ServerBootstrap{
private int mMaxSize = 1 ;
private bool mAlive = false ;
private IDecoder mDecoder ;
private IEncoder mEncoder;
//设置链接的最大个数
public ServerBootstrap SetMaxSize(int size){
this.mMaxSize = size ;
return this;
}
//设置链接是否保持活跃
public ServerBootstrap SetKeepAlive(bool alive){
this.mAlive = alive ;
return this;
}
//设置消息进来的解码
public ServerBootstrap SetDecoder(IDecoder decoder){
this.mDecoder = decoder ;
return this;
}
//设置消息回传的编码
public ServerBootstrap SetEncoder(IEncoder encoder){
this.mEncoder = encoder ;
return this;
}
}
使用链式方法操作ServerBootstrap对象
public class Server{
public static void main(string args){
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.SetMaxSize(128)
.SetKeepAlive(false)
.SetDecoder(new IDecoder())
.SetEncoder(new IEncoder());
}
}
这种做法在Java中相当常见,而目前游戏的短连服务器基本都使用Java完成,Netty中的对象大量的使用了链式编程的方式,使结构更加直观。当然Java服务器是有弊端的,最大的弊端就是不能热修复,另外对长链接的支持性并不好。所以在一些同步要求比较高的游戏中很少使用,长连服务器一般使用C+Lua去实现热修复,以及长连同步的需求。这个都是题外话了,有兴趣的同学可以自己去搜索一些资料看看,后面如果有时间,博主也会出一个专题带大家了解一下游戏服务器的知识。