责任链模式与中间件原理

发布于:2025-07-13 ⋅ 阅读:(20) ⋅ 点赞:(0)

责任链模式

责任链使用场景

image

责任链代码实现

/// <summary>
/// 请假请求
/// </summary>
class LeaveRequest
{
    /// <summary>
    /// 请假天数
    /// </summary>
    public int LeaveDays { set; get; }

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { set; get; }
}
/// <summary>
/// 抽象管理类
/// </summary>
abstract class AbstractManagerLeaveHandler
{
    public AbstractManagerLeaveHandler AbstractLeaveHandler { get; set; }
    public abstract void HandlerLeaveRequest(LeaveRequest request);
}
/// <summary>
/// 部门经理
/// </summary>
class BMManagerLeaveHandler : AbstractManagerLeaveHandler
{
    private readonly int allowedDays = 3; // 允许天数
    private string handlerName; // 领导名称
    public BMManagerLeaveHandler(string name)
    {
        this.handlerName = name;
    }
    public override void HandlerLeaveRequest(LeaveRequest request)
    {
        if (request.LeaveDays <= this.allowedDays)
        {
            Console.WriteLine("部门经理:" + this.handlerName + ",已批准请假;流程结束。");
            return;
        }
        AbstractLeaveHandler?.HandlerLeaveRequest(request);
    }
}
/// <summary>
/// 主管
/// </summary>
class ZGManagerLeaveHandler : AbstractManagerLeaveHandler
{
    private readonly int allowedDays = 7; // 允许天数
    private string handlerName; // 领导名称
    public ZGManagerLeaveHandler(string name)
    {
        this.handlerName = name;
    }
    public override void HandlerLeaveRequest(LeaveRequest request)
    {
        if (request.LeaveDays <= this.allowedDays)
        {
            Console.WriteLine("主管:" + this.handlerName + ",已批准请假;流程结束。");
            return;
        }
        AbstractLeaveHandler?.HandlerLeaveRequest(request);
    }
}
/// <summary>
/// 总经理
/// </summary>
class ZManagerLeaveHandler : AbstractManagerLeaveHandler
{
    private readonly int allowedDays = 20; // 允许天数
    private string handlerName; // 领导名称
    public ZManagerLeaveHandler(string name)
    {
        this.handlerName = name;
    }
    public override void HandlerLeaveRequest(LeaveRequest request)
    {

        if (request.LeaveDays <= this.allowedDays)
        {
            Console.WriteLine("总经理:" + this.handlerName + ",已批准请假;流程结束。");
            return;
        }
        AbstractLeaveHandler?.HandlerLeaveRequest(request);
    }
}
LeaveRequest lr = new();
lr.Name = "小明";
lr.LeaveDays = 8;

ZGManagerLeaveHandler zGManagerLeaveHandler = new ("张飞");
BMManagerLeaveHandler bMManagerLeaveHandler = new ("诸葛亮");
ZManagerLeaveHandler zManagerLeaveHandler = new("刘备");

bMManagerLeaveHandler.AbstractLeaveHandler = zManagerLeaveHandler;
zGManagerLeaveHandler.AbstractLeaveHandler = bMManagerLeaveHandler;

zGManagerLeaveHandler.HandlerLeaveRequest(lr);

Middleware实现原理

按责任链模式实现

创建请求类和中间件类。

/// <summary>
    /// http上下文类(用于获取HttpRequest和HttpResponse)
    /// </summary>
    class HttpContext
    {
        public HttpRequest httpRequest { set; get; } // 请求输入类
        public HttpResponse httpResponse { set; get; } // 请求响应输出
    }

    /// <summary>
    /// http请求类
    /// </summary>
    class HttpRequest
    {
        /// <summary>
        /// 请求url
        /// </summary>
        public string requestUrl;
    }
    /// <summary>
    /// http响应类
    /// </summary>
    class HttpResponse
    {
    }
/// <summary>
    /// 中间件抽象类
    /// </summary>
    abstract class Middleware
    {
        // 下一个中间件
        public Middleware nextMiddleware { set; get; }

        /// <summary>
        /// 处理请求
        /// </summary>
        /// <param name="request"></param>
        public abstract void HandlerRequest(HttpContext httpContext);
    }
class Default404Middleware : Middleware
{
    /// <summary>
    /// 中间件是否终止条件
    /// </summary>
    private string token = "404";
    public override void HandlerRequest(HttpContext httpContext)
    {
        Console.WriteLine($"执行默认404中间件");
        // 判断请求url是否包含token,包含则终止
        if (httpContext.httpRequest.requestUrl.Contains(token))
        {
            Console.WriteLine($"默认40中间件终止了");
            return;
        }
        nextMiddleware?.HandlerRequest(httpContext);
    }
}
class Default500Middleware : Middleware
{
    /// <summary>
    /// 中间件是否终止条件
    /// </summary>
    private string token = "500";
    public override void HandlerRequest(HttpContext httpContext)
    {
        Console.WriteLine($"执行默认500中间件");
        // 判断请求url是否包含token,包含则终止
        if (httpContext.httpRequest.requestUrl.Contains(token))
        {
            Console.WriteLine($"默认500中间件终止了");
            return;
        }
        nextMiddleware?.HandlerRequest(httpContext);
    }
}
class HttpsMiddleware : Middleware
{
    /// <summary>
    /// 中间件是否终止条件
    /// </summary>
    private string token = "https";
    public override void HandlerRequest(HttpContext httpContext)
    {
        Console.WriteLine($"执行默认https中间件");
        // 判断请求url是否包含token,包含则终止
        if (httpContext.httpRequest.requestUrl.Contains(token))
        {
            Console.WriteLine($"默认https中间件终止了");
            return;
        }
        nextMiddleware?.HandlerRequest(httpContext);
    }
}

像责任链模式一样调用

HttpContext httpContext = new();
HttpRequest httpRequest = new()
{
    requestUrl = "500"
};
httpContext.httpRequest = httpRequest;

HttpsMiddleware httpsMiddleware = new();
Default404Middleware default404Middleware = new();
Default500Middleware default500Middleware = new();

httpsMiddleware.nextMiddleware = default404Middleware;
default404Middleware.nextMiddleware = default500Middleware;

httpsMiddleware.HandlerRequest(httpContext);

第一次改造

但是如果要想加入中间件,责任链这样的调用就会很麻烦,于是去改造代码,加入建造者模式。

/// <summary>
/// 封装中间件
/// </summary>
class Application
{
    /// <summary>
    /// 中间件链集合(中间件管道)
    /// </summary>
    private List<Middleware> middlewares = new List<Middleware>();

    public Application(){ }

    /// <summary>
    /// 外部添加中间件
    /// </summary>
    /// <param name="middleware"></param>
    public void AddMiddleware(Middleware middleware)
    {
        middlewares.Add(middleware);
    }


    /// <summary>
    /// 创建动态中间链(通用)
    /// 1、头部中间件
    /// 2、中间变量
    /// </summary>
    /// <returns></returns>
    public Middleware GetMiddleware()
    {
        // 1、头部节点
        Middleware headerMiddleware = null;

        // 2、中间变量
        Middleware middlewareMiddle = null;

        // 3、形成中间件链
        foreach (var middleware in middlewares)
        {
            if (headerMiddleware == null)
            {
                middlewareMiddle = middleware;

                headerMiddleware = middlewareMiddle;
            }
            else
            {
                middlewareMiddle.nextMiddleware = middleware;
                middlewareMiddle = middleware;
            }
        }
        return headerMiddleware;
    }
}
/// <summary>
/// 中间件集合建造者
/// </summary>
class ApplicationBuilder
{
    private Application application = new Application();
    public void AddMiddleware(Middleware middleware)
    {
        application.AddMiddleware(middleware);
    }
    public Application Build()
    {
        return application;
    }
}

上面代码中把中间件都添加到集合 middlewares 中,再通过 GetMiddleware 方法动态创建出中间件链。

以下在客户端调用。

HttpContext httpContext = new();
HttpRequest httpRequest = new()
{
    requestUrl = "500"
};
httpContext.httpRequest = httpRequest;

ApplicationBuilder applicationBuilder = new ApplicationBuilder();
applicationBuilder.AddMiddleware(new HttpsMiddleware());
applicationBuilder.AddMiddleware(new Default404Middleware());
applicationBuilder.AddMiddleware(new Default500Middleware());
Application application = applicationBuilder.Build();

var middleware = application.GetMiddleware();

middleware.HandlerRequest(httpContext);

第二次改造

虽然责任链调用已经完成了封装,遵循了开闭原则,但是添加中间件 AddMiddleware 方法依然会随着中间件增加而增多,客户端代码不稳定。

于是我们使用了扩展方法,并引入 Startup 类。

static class HttpsMiddlewareExtension
{
    public static ApplicationBuilder AddHttpsMiddleware(this ApplicationBuilder applicationBuilder)
    {
        applicationBuilder.AddMiddleware(new HttpsMiddleware());
        return applicationBuilder;
    }
}
static class Default404MiddlewareExtension
{
    public static ApplicationBuilder AddDefault404Middleware(this ApplicationBuilder applicationBuilder)
    {
        applicationBuilder.AddMiddleware(new Default404Middleware());
        return applicationBuilder;
    }
}
static class Default500MiddlewareExtension
{
    public static ApplicationBuilder AddDefault500Middleware(this ApplicationBuilder applicationBuilder)
    {
        applicationBuilder.AddMiddleware(new Default500Middleware());
        return applicationBuilder;
    }
}
/// <summary>
/// 启动类
/// </summary>
class Startup
{
    public void Configure(ApplicationBuilder builder)
    {
        builder.AddHttpsMiddleware();
        builder.AddDefault404Middleware();
        builder.AddDefault500Middleware();       
    }
}

这样客户端代码就稳定了。

HttpContext httpContext = new();
HttpRequest httpRequest = new()
{
    requestUrl = "500"
};
httpContext.httpRequest = httpRequest;

ApplicationBuilder applicationBuilder = new ApplicationBuilder();
Startup startup = new();
startup.Configure(applicationBuilder);

Application application = applicationBuilder.Build();

var middleware = application.GetMiddleware();

middleware.HandlerRequest(httpContext);

以后每次想添加中间件,只需要添加中间件类和扩展类,再往 Startup 类中加入就可以了,客户端调用代码完全不用动。

image


网站公告

今日签到

点亮在社区的每一天
去签到