一、为什么要有builder设计模式?
一般情况下,我们初始化对象,是下面这样的:
1、假设我们有一个Phone类,该类有属性(操作系统os、处理器processor、屏幕尺寸screenSize、电池battery和品牌brand):
package Phone;
public class Phone {
private String os;
private String processor;
private double screenSize;
private int battery;
private String brand;
public Phone(String os, String processor, double screenSize, int battery, String brand) {
this.os = os;
this.processor = processor;
this.screenSize = screenSize;
this.battery = battery;
this.brand = brand;
}
@Override
public String toString() {
return "Phone{" +
"os='" + os + '\'' +
", processor='" + processor + '\'' +
", screenSize=" + screenSize +
", battery=" + battery +
", brand='" + brand + '\'' +
'}';
}
}
我们为该类创建了Constructor,并重写了toString方法。
此时,我们要在Shop类中实例化Phone对象的方式是这样的:(直接使用构造器初始化)
package Phone;
public class Shop {
public static void main(String[] args) {
Phone phone = new Phone("Android","麒麟",1080,9999,"HuaWei");
System.out.println(phone);
}
}
输出结果为:
Phone{os='Android', processor='麒麟', screenSize=1080.0, battery=9999, brand='HuaWei'}
Tips:在sout语句里输出实例对象,它会默认调用该对象类的toString方法。(通俗的说就是sout(phone),会默认调用Phone类中的toString方法)
以上这种方式的弊端:
如果我只想定义phone对象的部分参数,例如:我只想买华为(brand)的大屏幕(screenSize)手机,至于处理器(processor)、电池容量(battery)和操作系统(os)我都不懂也不关心。那么我们就要再定义一个只需传入brand和screenSize参数的构造器,就很麻烦。(可能买手机的这个例子并不觉得麻烦,但很麻烦的情况是会出现的)
此时,就可以使用builder模式,来解决上述的弊端。
二、builder模式使用
- 首先我们创建一个PhoneBuilder类,该类拥有Phone类的所有属性。
- 为PhoneBuilder类中的属性创建setter方法,这些setter方法的返回值类型是PhoneBuilder。
- 在PhoneBuilder类中写build()方法,目的是返回Phone类的实例化对象。
PhoneBuilder类的代码如下:
package Phone;
public class PhoneBuilder {
private String os;
private String processor;
private double screenSize;
private int battery;
private String brand;
public PhoneBuilder setOs(String os) {
this.os = os;
return this; //这里的return this,按我的理解就是返回设置了Os属性的PhoneBuilder对象,如果不对,请指正。
}
public PhoneBuilder setProcessor(String processor) {
this.processor = processor;
return this;
}
public PhoneBuilder setScreenSize(double screenSize) {
this.screenSize = screenSize;
return this;
}
public PhoneBuilder setBattery(int battery) {
this.battery = battery;
return this;
}
public PhoneBuilder setBrand(String brand) {
this.brand = brand;
return this;
}
public Phone build(){
return new Phone(os,processor,screenSize,battery,brand); //括号里面的参数os,processor,screenSize,battery,brand,其实对应的就是最上面的属性,即把PhoneBuilder的属性当作参数穿给Phone的构造器
}
}
此时,我们在Shop类中实例化Phone对象,是这样做的:
我们实例化一个PhoneBuilder类,然后调用PhoneBuilder类中的setOs()、setProcessor()、setScreenSize()、setBattery()、setBrand()方法来设置phone对象的参数。最后调用PhoneBuilder类中的build()方法,将我们设置了参数的phone对象返回,以此完成phone对象的初始化。
package Phone;
public class Shop {
public static void main(String[] args) {
Phone phone = new PhoneBuilder()
.setOs("Android")
.setProcessor("麒麟")
.setScreenSize(1080)
.setBattery(9999)
.setBrand("HuaWei")
.build();
System.out.println(phone);
}
}
输出结果为:
Phone{os='Android', processor='麒麟', screenSize=1080.0, battery=9999, brand='HuaWei'}
这样做的好处在于,假设我只想买华为(brand)的大屏幕(screenSize)手机,至于处理器(processor)、电池容量(battery)和操作系统(os)我都不懂也不关心。那么就可以像下面这样做:(而不用再去写只有brand和screenSize两个参数的构造器)
package Phone;
public class Shop {
public static void main(String[] args) {
Phone phone = new PhoneBuilder()
.setScreenSize(1080) //个人理解:这里的setScreenSize等方法,其实是在给PhoneBuilder对象设置属性。只不过在最后的build方法里面,将PhoneBuilder对象的这些属性值,当作参数传递给Phone对象的构造器,以此初始化Phone对象。
.setBrand("HuaWei")
.build();
System.out.println(phone);
}
}
输出结果为:
Phone{os='null', processor='null', screenSize=1080.0, battery=0, brand='HuaWei'}
可以看见,没有设定的参数os、processor和battery,都是等于默认的初始值。
以上就是关于builder设计模式的简单介绍。