换个角度理解设计模式之建造者模式构建httpClient

系列文章的目录:https://blog.csdn.net/hjkl950217/article/details/89490709

记住:设计模式重理解轻照搬

背景

如果你进入微服务化,并且以http的方式做远程调用的话,有没有觉得需要处理各种各样的http需求?就我自己而言,我遇到下面的情况:

  1. 普通的调用
  2. 带Oauth认证头的调用,并且认证的token可能是从配置服务中获取的
  3. 返回的数据是文件流
  4. 记录请求和返回时的数据到日志中
  5. 支持自定义的格式,比如添加masagePack的支持
  6. 其它…

这些会经常用,但是又不想每次都自己手写。有没有办法可以方便的按需求配置http的调用呢? 答案是有的,这就是今天讲的用建造者模式构建httpClient

PS:示例中会用几个对象的模拟http调用中的对象,本文只是分享这种扩展的方式,而不是具体怎么编写httpClient.毕竟每个业务小组面对的http需求是不相同的。文章中只包括核心部分,具体细节可以下载附件中的代码1,很少。

什么是建造者模式?

官方的定义网上一查就有,这里我说说我的理解:用一系列的对象或委托,按需求快速组装出我们使用的工具.
有人用过万用螺丝刀么?就像下面这样:
万用螺丝刀
这个工具有很多功能,而且使用时也能快速组装。但他的核心点其实只有一个,是他的通用螺口
在这里插入图片描述
只要工具头适配了这个螺口,就可以与握把组后成我们需要的工具。

而代码中的这种快速组合工具的方式,就是建造者模式。

分析问题

在http的调用中,我们的通用螺口其实是header,它的数据全是KV型的,标记了请求\响应行为中的具体参数细节,拿到了头,我们就知道怎么处理数据、做什么样的控制等等。那么我们只要把http中调用过程中,对请求与响应的过程开放出来就好了

核心代码

来看看开放后的处理过程:

        //只是模拟,并没有真实的http调用,所以这里的响应体是mock的

        public Response SendHttp(Request request, Response mockResponse = null)
        {
            this.RequestActions.ForEach(t => t.Invoke(request));//调用外部注入的方法处理请求体

            Console.WriteLine($"基础Http接口被调用!");
            Console.WriteLine($"url:{request.Url}");
            Console.WriteLine($"Http动作方法:{request.Method}");
            Console.WriteLine("Header:");
            foreach (var item in request.Headers)
            {
                Console.WriteLine($"headerName:{item.Key} \t value:{item.Value}");
            }

            Console.WriteLine($"body:\t\n{request.Body}");
            Console.WriteLine();
            
            mockResponse = mockResponse ?? new Response();
            this.ResponseActions.ForEach(t => t.Invoke(mockResponse));//同上
            return mockResponse;
        }

这里的RequestActionsResponseActions都是属性,由外部添加处理方法进来。然后在代码执行时对请求或响应进行处理。

然后再在建造者类中,进一步简化处理过程:

        public static HttpClientBuilder UseOAuth(this HttpClientBuilder httpClientBuilder, string toekn)
        {
            Action<WebClient> useOauth = webClient =>
            {
                //这里还少了一个代码,思考下少了什么
                webClient.RequestActions
                    .Add(t => t.Headers.Add(new KeyValuePair<string, string>("OAuth", toekn)));
            };

            httpClientBuilder.Actions.Add(useOauth);

            return httpClientBuilder;
        }

这里其实是对OAuth头的进一步封装,让我们的工具头可以快速适配!

学会这一个点,是不是可以自己再扩充其它的功能呢?比如上面提到的MasagePack协议,只需要添加一套代码:判断到Content-TypemsgPack,则使用MasagePack的序列化器解析数据。

建造者的意义

其实你看上面的代码会发现UseOAuth方法似乎只是一个封装而已,没什么用。其实不然。。

我对建造者的理解,其实是把他当成一个桥梁,将底层逻辑开发者之间快速适配的桥梁。 示例代码中的HttpClientBuilder只是给扩展方法使用的,本身没什么逻辑。扩展方法中具体定义了如何处理请求或响应,然后由调用者非常方便的组合他们需要的工具。

毕竟,框架需要提供简单易用的方法给别人呀。

使用

使用的地方其实很简单了:

        private static void Main(string[] args)
        {
            Request request = new Request()
            {
                Url = "http://test.com",
                Method = "POST",
                Body = "{\"demo\":\"demoString\"}"
            };

            WebClient client = HttpClientBuilder.CreateDefaultHttpClientBuilder()
                .BuildWebClient();

            //此时的client只是最基础的client

            client.SendHttp(request);

            client = HttpClientBuilder.CreateDefaultHttpClientBuilder()
                .UseOAuth("testToken")
                .UseOAuth("testToken2")
                .BuildWebClient();

            //此时的client就拥有了处理OAuth头的能力

            client.SendHttp(request);
            Console.WriteLine("End");
            Console.ReadLine();
        }

输出:
在这里插入图片描述

有没有发现OAuth的头有2个? 现在知道少了什么代码不?这里引出一个潜规则出来。。

建造者模式的潜规则

如果是相同的方法被调用多次,只有最后一个方法生效才对!

上面缺失的代码中,其实是少了对Oauth头的判断:

  1. 如果已经存在 则更新里面的值
  2. 如果不存在,则新加

与工厂模式的区别

先说下建造者模式的缺点:强调方法被调用的顺序,需要使用者对建造过程有一定的熟悉。

知道缺点了,再来看与工厂模式的区别就很清楚了~

工厂模式更适合“品种少,变化不多,但构建过程复杂”的场景,而建造者模式更适合"品种多样,变化很多,单个品种构建过程一般复杂"的场景。 有的时候还可以联合使用!! 工厂模式在构建产品的具体代码时,使用建造者模式来构建。


  1. 建造者模式 ↩︎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值