这是我参与更文挑战的第3天,活动详情查看:更文挑战
Builder模式
Builder模式通常是作为配置类构造器将配置构建和表示区分开来,同时又将配置从目标类中隔离,省去过多setter方法。常见Builder模式通过链式调用,可以让代码更加简介、清晰。
构造函数
平常我们创建一个类的时候是通过编写构造方法来实现。当我们需要初始化多少个配置时就调用对应的重载函数。这个过程很容易在开发过程中出错,不方便开发者直观了解到所带入参配置项具体是什么含义。
class Computer{
private CPU cpu;
private KeyBoard keyboard;
private Display display;
private Power power;
private Raw raw;
public Computer(CPU cpu){
this.cpu = cpu;
}
public Computer(CPU cpu,KeyBoard keyboard){
this.cpu = cpu;
this.keyboard = keyboard;
}
....
public Computer(CPU cpu,KeyBoard keyboard,Display display,Power power,Raw raw){
this.cpu = cpu;
this.keyboard = keyboard;
this.power = power;
this.raw = raw;
}
}
复制代码
setter方法
下面再换个方式,构建函数是空实现,将配置项都以setter方法做初始化实现。通过setter确实解决了构造函数多个配置入参容易造成配置项搞混参数错误的情况,在代码阅读上有了提升。咋一看setter方式好像可以满足开发要求,但这也存在弊端配置项不稳定。对象状态容易发生变化,在开发过程中随时可以调用setter改变配置项。
class Computer{
private CPU cpu;
private KeyBoard keyboard;
private Display display;
private Power power;
private Raw raw;
public Computer(){}
public void setCPU(CPU cpu){
this.cpu = cpu;
}
public void Display(Display display){
this.display = display;
}
....
public void setRaw(Raw raw){
this.raw = raw;
}
}
复制代码
builder
为了解决以上问题,采用Builder模式是最佳选择。
Computer类当中实现静态类Builder,Builder拥有和Computer一样的配置项。Computer构造函数是私有的,不能直接创建Computer对象,只能通过Builder去创建Computer。同时Builder是链式调用,设置配置项结束以后以build()方法结尾装配出最终需要实例化的Computer对象。由此就保证配置形式清晰、保护配置项不被篡改。
class Computer{
private CPU cpu;
private KeyBoard keyboard;
private Display display;
private Power power;
private Raw raw;
private Computer(Builder builder){
this.cpu = builder.cpu;
this.keyboard = builder.keyboard;
this.display = builder.display;
this.power = builder.power;
this.raw = builder.raw;
}
public static class Builder{
private CPU cpu;
private KeyBoard keyboard;
private Display display;
private Power power;
private Raw raw;
public Builder(CPU cpu){
this.cpu=cpu;
}
public Builder setKeyBoard(KeyBoard keyBoard) {
this.keyBoard = keyBoard;
return this;
}
public Builder setDisplay(Display display) {
this.display = display;
return this;
}
public Builder setDisplay(Display display) {
this.display = display;
return this;
}
public Builder setPower(Power Power) {
this.power = power;
return this;
}
public Builder setRaw(Raw raw) {
this.raw = raw;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
new Computer.Builder(xxxx)
.setDisplay(xxx)
.setKeyboard(xxx)
.build();
复制代码
拓展
插件
知道Builder模式之后在日常开发过程中如何快速编写Builder模式,一个类配置项一多手写就不是很好的处理方式。
Idea提供了Builder Generator插件自动生成静态类Builder。先编写一个需要Builder的工具类,然后alt+insert执行Builder即可自动生成Builder代码。
应用
Builder模式在实际开发中用途广大。
像是Android图片开源库Gilde采用的就是Builder模式。
Glide.with(this)
.load(url)
.placeholder(R.drawable.loading)
.error(R.drawable.error)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView);
复制代码
Glider的Builder模式调用流程描述非常清晰:
- 先初始化Glide上下文
- 预设加载图片地址
- 配置加载过程中的占位图
- 配置加载失败的占位图
- 配置缓存策略
- 装载图片显示的视图对象
对于客户端并不关心内部具体实现,只需要传递需要的配置参数就能实现图片加载。
总结
Builder模式具备良好的封装,只对外暴露需要的配置项不必知道内部细节,同时也相对独立后续容易扩展。不足之处就是增加了一份Builder实例,消耗内存。