?
上一讲我们介绍了工厂模式
可以用工厂类来构造一个对象
其实,归根结底
创建一个对象,都需要调用构造方法
Java编码推荐:每一个类都需要一个无参数的构造方法
而且默认无需定义
例如:
Class Car{
String model; // 型号
Float price; // 零售价
}
那么它就一定可以使用 new Car() 来创建
在 Factory 里也是如此,只是把 new 的过程交给了工厂方法
单例是最简单的设计模式
其实在Java体系中
只要一个对象是 static 那它仅会有一个
所以 单例模式基本上只有一种写法
public class MessageService{
private static MessageService service; // 唯一存在的对象
private MessageService(){
// TODO
}
public static MessageService getInstance(){
if(service==null){ // 首次调用时会创建
service=new MessageService();
}
return service;
}
}
先用 private 限定构造方法
因此,这类无法被其他类 new 创建
然后通过一个 public static 方法,用于对象创建调用
这样此对象有且只有一个
小知识:static 是静态的变量
很多同学可能不明白
其实可以换一种说法
叫他全局变量
它的生命周期是无限的
从程序启动到结束
跨越时间和对象、方法的界限
前面的案例都有一个大前提
构造方法必须是无参数的
不然呢,在 new 的时候还有参数
那该传几个参数?顺序呢?怎么传入呢?
都会是问题
因此,前面都是开胃菜
今天着重介绍的是 builder 建造者 模式
可能有些同学之前学过一些
在古老教程中
builder 模式的构成
包括 Builder、ConcreteBuilder、Director、Product 等部分
还给他们取了不同的名字
比如 产品、建产品的工人、监工等等
?
?编辑?
?编辑
我们今天简化一下
就强调两个点:Builder 和 Product
Product 代表的是建的对象,决定建什么东西
Builder 代表建东西的类,决定怎么建
与工厂做类,可以认为 Builder 就是 建 Product 的工厂
但做法大相径庭
Builder 的应用场景
是为了解决有参数构造的问题
并且参数往往很复杂
举例:
Class Car{
String model; // 型号
Float price; // 零售价
public Car(String model, Float price){
this.model=model;
this.price=price;
}
}
以上这个例子,就是构造对象必须初始化值的一种做法
如果我们要new一个对象
往往这样写:
Car wl_mianbao=new Car("五菱EV50", 98800F);
Car df_mianbao=new Car("东风小康", 79999F);
但程序员都知道
需求总是改
忽然有一天
需要增加属性
Class Car{
String model; // 型号
Float price; // 零售价
String color; // 颜色
public Car(String model, Float price){
this.model=model;
this.price=price;
}
public Car(String model, Float price, String color){
this.model=model;
this.price=price;
this.color=color;
}
}
为了增加一个属性color
我们得重新写一个构造器,支持3个参数
并且为了兼容老版本的代码
2个参数的构造器还得留着
这种写法是不健康的
试想现在是3个参数,万一又加呢?
我是不是还得写4参数、5参数的构造器
而且参数之间还可能有排列组合、顺序的问题
代码越写就越混乱
以上问题可以转换一个思路
用setter方法解决
如下:
Class Car{
String model; // 型号
Float price; // 零售价
String color; // 颜色
public void setModel(String model){
this.model=model;
}
public void setPrice(Float price){
this.price=price;
}
public void setColor(String color){
this.color=color;
}
}
回归了无参数构造
但是需要依次调用setter
才能完整的创建一个对象
Car xiaomian=new Car();
xiaomian.setModel("五菱");
xiaomian.setPrice(98800F);
xiaomian.setColor("星光金");
这种方法就规避了参数多样化的问题
但setter主要的作用是字段赋值
在这里借用了取巧的方法
虽然能解决大部分问题
但仍然有一些不完美的地方
例如:
哪些参数是可有可无的?
会不会漏传参数?
等等
这个时候,就需要引入builder类
通常是建一个内部类来解决
public class Car {
String model; // 型号
Float price; // 零售价
String color; // 颜色
private Car(Builder carbuilder) {
this.model=carbuilder.model;
this.price=carbuilder.price;
this.color=carbuilder.color;
}
public static class Builder{
private String model;
private Float price;
private String color;
public Builder(String model) { // 必要参数构造
this.model=model;
}
public Builder() { // 可选参数构造
}
public Builder model(String model) {
this.model=model;
return this;
}
public Builder price(Float price) {
this.price=price;
return this;
}
public Builder color(String color) {
this.color=color;
return this;
}
public Car build() {
return new Car(this);
}
}
}
调用时,变成了这样:
Car xiaocar=new Car.Builder()
.model("五菱")
.price(98800F)
.color("星光金")
.build();
对比一下,setter和builder的区别
主要体现在构造调用的方法
setter的前后文是无关的
而builder是一种链式调用的形式
直到最后一句 build() 走完
才真正创建了目标对象
看一下大家常用的类,举两个例子
例子一:JWT的令牌构造
JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject) / 主题
.setIssuer(userid) // 签发者
.setIssuedAt(now) // 签发时间
.signWith(key); // 签名算法以及密匙
.setExpiration(expDate) // 过期时间
.compact();
例子二:工作流的实例启动
ProcessInstance instance = runtimeService.createProcessInstanceBuilder();
.processDefinitionId(processdefinitionid);
.name(processname);
.businessKey(key);
.tenantId(tenantid);
.start();
这种分步骤创建的方式
从阅读上很清晰
可以将一个复杂的步骤化简为零
所以对程序员来说
可以降低调用的复杂度
刚才我们经历了一个简单类型
逐步复杂的过程
其实建一个普通类型还没什么
但builder类的代码有点太多了
还要写内部类,很多人不习惯
其实只要使用 lombok 就可以了
首先maven引用
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
然后在类上只要增加一个注解即可
@Builder
public class Car {
String model; // 型号
Float price; // 零售价
String color; // 颜色
}
调用方法:
Car xiaocar=Car.builder()
.model("五菱")
.price(98800F)
.color("星光金")
.build();
是不是很简单了呢?
很多设计模式都是来自平时遇到的问题
通过一些编程小技巧来解决问题
建造者模式应对的是构造参数较多、参数可变的情形
后续的系列中会介绍更加复杂的结构性模式
敬请期待吧
?
本文系转载,前往查看
如有侵权,请联系?cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系?cloudcommunity@tencent.com 删除。