前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈模式之建造者模式(由来和通用写法)

漫谈模式之建造者模式(由来和通用写法)

作者头像
孟君
发布2023-03-03 19:55:14
3440
发布2023-03-03 19:55:14
举报

今天我们分享另外一个创建型的模式:建造者模式。在讲解建造者模式之前,我们首先来看一个需求示例。

规范化日志需求思考

案例简单说明

假设有一个简单需求,需要对不同业务场景的日志进行统一规范化格式打印或者上送至Kafka。

下面给出一个简单规范化日志类,包含场景、服务名、方法名、耗时、code和错误信息。

图片
图片

构造函数

针对多种场景的不同标准需要,可能包含多个构造函数的使用,以满足不同场景下日志输出。如:

图片
图片

静态方法代替构造函数

当构造函数有多个的时候,比如有2个类型都是3个String类型的参数,但是不同字段,这时候构造函数只能有一个。

此时,我们可能会使用静态方法代替构造函数来做,只要取一个能区分场景的方法名字即可。

比如:

代码语言:javascript
复制
public static RegularLogInfo getBasicLogInfo(String serviceName,           String methoodName, long costTime) {    //DO SOMETHING  } ... ...

静态方法虽然解决了一定的问题,但是如果随着需要打印的内容增多。无论构造函数还是静态方法创建对象都变得麻烦。

比如;

增加traceId和spanId,又如增加集群信息(dc、clusterName、appName)等等。

面对属性字段较多、对象形态多样性的场景,今天的主角【建造者模式】闪亮登场。

建造者模式简介

意图

建造者模式是一种创建型的模式,其意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

基本结构

图片
图片
  • Builder 
    • 为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder
    • 实现Builder的接口以构造和装载该产品的各个部件
    • 定义并明确它所创建的表示
  • Director
    • 构造一个使用Builder接口的对象
  • Product
    • 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。 包括定义组成部件的类,包括将这些部件装配成最终产品的接口。

Note:建造者模式是体现局部和整体关系的,产品是一步步构建,最终形成的一定是一个整体。

就比如顾客去餐厅购买一份儿童餐,跟收银员说要汉堡、饮料、甜甜圈有额外的玩具等,最终顾客得到是包含所有的儿童餐,是一个整体

图片
图片

建造者模式实现

日志类增加属性

图片
图片

创建一个Builder

编写Builder类的一个简单方法就是使用如下几个步骤:

编写Builder类

将RegularLogInfo的属性都放到Builder类中,如:

图片
图片

增加一个静态的newBuilder()方法, 用于返回Builder对象

图片
图片

以每个属性的名字,命名方法,赋值后返回本身也就是this

图片
图片

最后,增加一个build()方法,赋值后返回具体对象即可,本例为RegularLogInfo。

图片
图片

调用示例 

3个步骤即可

  • 调用newBuilder()方法,获取Builder对象
  • 赋值
  • 调用build()方法返回最终对象

如:

图片
图片

这样,使用Builder模式创建一个规范化日志对象就完成了。只要按照具体场景进行赋值即可,非常灵活。

其它写法

当然,除了上述的写法外,也可以将Builder写到具体类里面。比如,使用Lombok@Builder注解,其就是通过修改抽象语法树,在类内部增加一个静态内部类Builder来做的。如下图所示:

图片
图片

有兴趣的读者可以深入去分析一下。

一个通用的写法

上述场景,我们为RegularLogInfo类写了一个RegularLogInfoBuilder。如果类似场景较多,我们是不是需要编写多个Builder来完成。

那么问题来了,有什么通用的方法吗,写一个到处能用的那种

答案是肯定的。其实,使用Lombok@Builder注解,就是一种通用的做法

另外,我们可以借助JDK1.8后Supplier来实现一个通用的Builder构建器写法。有兴趣的读者可以参考之前的博文:一个通用的 Builder构建器写法

至此,建造者模式的由来和通用写法思考就完成了。

最后思考一个问题?

最后,我们再来思考一下? 

如果Builder()创建后,赋值需要按照一定的顺序,也就是要按照一定的步骤,我们该如何处理呢?比如,先赋值环境信息env,再赋值trace信息,最后赋值业务信息biz。如:

代码语言:javascript
复制

RegularLogInfo regularLogInfo = 
                          RegularLogInfoBuilder.newBuilder()
                          .env(envInfo)
                          .trace(traceInfo)
                          .biz(bizInfo)
                          .build();

在下一篇博文中,我们一起来完成这样的操作。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 规范化日志需求思考
  • 建造者模式简介
  • 建造者模式实现
  • 一个通用的写法
  • 最后思考一个问题?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档