前言
建造者模式即BUilder模式,看名字就可知是一种创建型模式。主要是解决
- 构造方法中参数过多导致的可读性较差的问题;
- 在初始化时不必将所有参数进行设置的情况(通常有默认值)。
文中会举例进行演示,通过例子能够有一个更清晰的认识。
场景描述
许多游戏在进入游戏时,第一步往往是让我们选择角色的外形,如眼睛颜色,眼睛大小,发型,头发颜色,脸型等等。假设现在要创建一个小明,大眼,绿色的瞳孔,中分头,红色头发,鞋拔子脸。当然还有必填的姓名。
首先,我们创建一个Person的类,并改写toString方法便于测试。
public class Person {
private String name;//姓名必填
private String eyeSize;//眼睛大小
private String eyeColor;//眼睛颜色
private String hairStyle;//发型
private String hairColor;//头发颜色
private String face;//脸型
public Person(String name, String eyeSize, String eyeColor, String hairStyle, String hairColor, String face) {
this.name = name;
this.eyeSize = eyeSize;
this.eyeColor = eyeColor;
this.hairStyle = hairStyle;
this.hairColor = hairColor;
this.face = face;
}
@Override
public String toString() {
String s = "姓名:" + name + "\n"
+ "眼睛:" + eyeSize + "\n"
+ "眼睛颜色:" + eyeColor + "\n"
+ "发型:" + hairStyle + "\n"
+ "头发颜色:" + hairColor + "\n"
+ "脸型:" + face;
return s;
}
}
同时我们编写测试类,创建小明这个角色。在创建时我郁闷了,在通过构造方法对对象进行初始化时,我忘记了参数的顺序。虽然现在IDE都非常的智能,会对参数进行提示,但是还是影响了我的开发效率。
最后我们艰辛的创建完了这个简单的测试类
public static void main(String[] args) {
Person xiaoming = new Person("小明","大", "绿色", "中分", "红色", "鞋拔子脸");
System.out.println(xiaoming.toString());
}
输入结果如下:
姓名:小明
眼睛:大
眼睛颜色:绿色
发型:中分
头发颜色:红色
脸型:鞋拔子脸
老铁,没毛病。但是现在是只有6个参数的情况下,似乎还可以接受,但是如果再多几个,orz!!
使用Builder模式
首先来说说使用Builder模式有什么优点:
- 默认参数,无需对所有参数进行初始化;
- 将实现变成链式调用,增加了代码可读性。
现在不管角色的外形,我只想创建一个小明的对象,来看看Builder模式会怎么做:
public static void main(String[] args) {
Person xiaoming = new Person.Builder("小明").create();
System.out.println(xiaoming.toString());
}
图片.png
Are you kidding?就传了个必填项姓名就创建好了?仅用一行代码就创建好了这个对象。
在前言中讲到过一点,设置默认值。以上实现就是基于默认值的设置。
接下来就来到了紧张刺激的代码实现环节。Builder的实现
public class Person {
private String name;//姓名必填
//省略其他可选参数
private Person(Builder builder) { //1............
initialize(builder);
}
private void initialize(final Builder builder) {
name = builder.name;
//省略
}
public static class Builder {
//2..........
private String name;//姓名必填
private String eyeSize = "大";//眼睛大小
//省略
public Builder(String name) {
this.name = name;
}
public Builder setEyeSize(String eyeSize) {
this.eyeSize = eyeSize;
//3..........
return this;
}
//省略
//4..........
public Person create() {
return new Person(this);
}
}
@Override
public String toString() {
String s = "姓名:" + name + "\n"
+ "眼睛:" + eyeSize + "\n"
+ "眼睛颜色:" + eyeColor + "\n"
+ "发型:" + hairStyle + "\n"
+ "头发颜色:" + hairColor + "\n"
+ "脸型:" + face;
return s;
}
}
划一下重点:
- 因为我们要用过Builder来创建对象,所有需将Person类的构造方法私有化,且通过Builder来构建;
- 在Builder中初始化变量,对外部提供set方法;
- 实现链式的关键 return this;
- 设置完参数之后通过Person类的构造进行构建并返回实例对象。
继续创建一个好看点的小红:
Person xiaohong = new Person.Builder("小红")
.setEyeColor("蓝色")
.setEyeSize("大")
.setFace("鹅蛋脸")
.setHairStyle("大波浪")
.setHairColor("褐色")
.create();
是不是格外的清晰。
总结
将代码写成链式是非常优美的事情,像在Android开发中,我们可以将TitleBar的设置写成链式,也可以将RecyclerView的初始化过程写成链式;
看过dagger2生成的代码就可以看出,文中builder模式是仿造它的实现,要是没看过现在也可以转去看,相信会轻松许多;
完整代码移步gayhub。
网友评论