Unity 责任链模式

初学者,自用笔记

用于把“一个请求的处理逻辑”拆成多个独立的处理器(Handler),并按顺序串成一条链;请求沿链传递,每个处理器决定:处理它、补充处理、拦截终止、或交给下一个。这样可以把复杂的 if/else、switch、规则判断解耦成可插拔的步骤,方便扩展与重排

常用于任务系统、成就系统、技能判定等......

  • Request(请求对象)主要携带输入参数(例如:玩家、任务ID、事件类型)
  • Handler(抽象处理器):定义统一处理入口(如 Handle(request))并持有 next。
  • ConcreteHandler(具体处理器):实现具体规则/步骤(校验、过滤、转换、执行、日志、冷却判定等)。
  • Client(组链者/调用方):负责把各处理器按顺序组装成链,并发起请求。

简单例子

Request

public sealed class QuestRequest
{
    // 输入(由调用方填)
    public int PlayerId;
    public int QuestId;

    // 链上产物/状态(由处理器写)
    public bool Allowed = true;
    public string FailReason = "";
    
    // 控制责任链:是否继续往下传
    public bool StopPropagation = false;
}

Handler

public abstract class QuestHandler
{
    protected QuestHandler _next;

    public QuestHandler SetNext(QuestHandler next)
    {
        _next = next;
        return next; // 方便链式组装
    }

    // 统一入口:把 request 放进来
    public void Handle(QuestRequest request)
    {
        // 1.先由当前处理器处理
        OnHandle(request);

        // 2.决定是否继续传递
        if (request.StopPropagation) return;
        if (_next == null) return;

        // 3.交给下一个
        _next.Handle(request);
    }

    // 具体处理逻辑由子类实现
    protected abstract void OnHandle(QuestRequest request);
}

ConcreteHandler


public sealed class PrerequisiteQuestCheckHandler : QuestHandler
{
    // 检查前置任务是否满足(不满足则拒绝并中断链)
    protected override void OnHandle(QuestRequest request)
    {
        // 假设一个任务可能有多个前置任务ID
        var prereqQuestIds = FakeQuestDB.GetPrerequisites(request.QuestId);

        for (int i = 0; i < prereqQuestIds.Length; i++)
        {
            int prereqId = prereqQuestIds[i];

            if (!FakeQuestDB.IsCompleted(request.PlayerId, prereqId))
            {
                request.Allowed = false; // 不允许接取
                request.FailReason = $"";
                request.StopPropagation = true; // 拦截:后续不用检查了
                return;
            }
        }
    }
}

public sealed class LevelCheckHandler : QuestHandler
{
    // 检查玩家等级是否满足接取条件
    protected override void OnHandle(QuestRequest request)
    {
        int playerLevel = FakePlayerDB.GetLevel(request.PlayerId); // 查询玩家等级

        if (playerLevel < 10) // 未达标:拒绝并中断后续处理
        {
            request.Allowed = false;                // 标记不允许
            request.FailReason = "";  // 写入失败原因
            request.StopPropagation = true;         // 拦截:不再传给 next
        }
    }
}

public sealed class QuestStateCheckHandler : QuestHandler
{
    // 检查任务是否已完成(已完成则不能再接取)
    protected override void OnHandle(QuestRequest request)
    {
        bool isQuestAlreadyCompleted =
            FakeQuestDB.IsCompleted(request.PlayerId, request.QuestId); // 查询任务状态

        if (isQuestAlreadyCompleted) // 已完成:拒绝并中断后续处理
        {
            request.Allowed = false;                         // 标记不允许
            request.FailReason = ""; // 写入失败原因
            request.StopPropagation = true;                  // 拦截:不再传给 next
        }
    }
}

Client

public static class QuestAcceptFlow
{
    public static QuestRequest TryAcceptQuest(int playerId, int questId)
    {
        // 1.组装责任链(顺序很重要)
        QuestHandler head = new LevelCheckHandler();
        head.SetNext(new QuestStateCheckHandler());

        // 2.创建请求对象(携带输入)
        var request = new QuestRequest
        {
            PlayerId = playerId,
            QuestId = questId
        };

        // 3.发起请求,让 request 沿链流转
        head.Handle(request);

        // 4.返回 request(调用方读取结果)
        return request;
    }
}
全部评论

相关推荐

牛客44320985...:你的当务之急是把这个糖的要死的沟槽ide主题改了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务