建造者模式
概念
将构建一个复杂对象分成几个部分(多道工序),构建步骤顺序不一致会导致对象表示不同,原来我们直接 A a = new A(); a.setXXX() … A类有很多属性,如果后面需要修改构建步骤顺序时,改动量就很大。
建造模式:当创建复杂对象时,将对象的组成部件和装配这些部件方式(组装部件顺序)分离开,这样灵活的建造对应的对象。对象的构建和对象的表示进行分离。
由于构建的对象很复杂,所以就需要将类划分成几部分,这个几个部分就是下面看到的PhoneBuilder类中的几个方法,然后每个方法会进行set对应的属性值。最后会提供一个方法返回建造完成后的对象。
使用场景
(1)相同的方法,不同的执行顺序,产生不同的事件结果。
(2)多个部件都可以装配到一个对象中,但是产生的运行结果又不相同。
(3)产品类非常复杂,或者产品类中调用顺序不同产生不同的作用,这时候使用建造者模式非常是适合。
(4)当初始化一个复杂的对象,如:好多参数,且很多参数都具有默认值。
和工厂模式区别
通过下面的类图可以发现,和之前讲解的工厂方法模式类似,但是工厂方法模式是通过不同具体工厂获取对象,而建造者模式是通过不同具体构造器建造(初始化)对象,工厂方法模式可以和建造模式结合使用,工厂模式中的对象可以通过建造模式来建造。
类图
使用场景(3)的代码实例
Phone 手机的抽象类
/**
* @author dynamo2120
* @create 2018-09-28 12:01 PM
* @description 抽象产品 手机
**/
public abstract class Phone {
private String brand;
private String osPart1;
private String osPart2;
private String screen;
public String getBrand() {
return brand;
}
//设置商标
public void setBrand(String brand) {
this.brand = brand;
}
public String getOsPart1() {
return osPart1;
}
//初始化系统部件1
public void setOsPart1(String osPart1) {
this.osPart1 = osPart1;
}
public String getOsPart2() {
return osPart2;
}
//初始化系统部件2
public void setOsPart2(String osPart2) {
this.osPart2 = osPart2;
}
public String getScreen() {
return screen;
}
//初始化屏幕
public void setScreen(String screen) {
this.screen = screen;
}
//充电方式,由子类实现
public abstract void charge();
@Override
public String toString() {
return "Phone{" +
"brand='" + brand + '\'' +
", osPart1='" + osPart1 + '\'' +
", osPart2='" + osPart2 + '\'' +
", screen='" + screen + '\'' +
'}';
}
}
ApplePhone 具体的手机
/**
* @author dynamo2120
* @create 2018-09-28 12:04 PM
* @description 苹果手机
**/
public class ApplePhone extends Phone {
@Override
public void charge() {
System.out.println("普通冲电");
}
}
SamsungPhone 具体的手机
/**
* @author dynamo2120
* @create 2018-09-28 12:05 PM
* @description 三星手机
**/
public class SamsungPhone extends Phone {
@Override
public void charge() {
System.out.println("快冲电");
}
}
PhoneBuilder 抽象手机建造者
/**
* @author dynamo2120
* @create 2018-09-28 2:29 PM
* @description 抽象的手机建造者
*
* 将对象的建造和表示分离开
**/
public interface PhoneBuilder {
//构造商标
void buildBrand();
//构造系统组件
void buildOs();
//构造屏幕
void buildScreen();
Phone createPhone();
}
ApplePhoneBuilder 具体建造者
/**
* @author dynamo2120
* @create 2018-09-28 2:32 PM
* @description 苹果手机建造类
**/
public class ApplePhoneBuilder implements PhoneBuilder {
private ApplePhone applePhone = new ApplePhone();
@Override
public void buildBrand() {
applePhone.setBrand("Aapple");
}
@Override
public void buildOs() {
applePhone.setOsPart1("ios part1");
applePhone.setOsPart2("ios part2");
}
@Override
public void buildScreen() {
applePhone.setScreen("screen1");
}
@Override
public Phone createPhone() {
return applePhone;
}
}
SamsungPhoneBuilder 具体建造者
/**
* @author dynamo2120
* @create 2018-09-28 2:32 PM
* @description
**/
public class SamsungPhoneBuilder implements PhoneBuilder {
private SamsungPhone samsungPhone = new SamsungPhone();
@Override
public void buildBrand() {
samsungPhone.setBrand("samsung");
}
@Override
public void buildOs() {
samsungPhone.setOsPart1("android part1");
samsungPhone.setOsPart2("android part2");
}
@Override
public void buildScreen() {
samsungPhone.setScreen("screen2");
}
@Override
public Phone createPhone() {
return samsungPhone;
}
}
Director 指挥者,如何通过PhoneBuilder提供的方法进行组装这些部件
/**
* @author dynamo2120
* @create 2018-09-28 2:53 PM
* @description 指导对象建造步骤,也就是初始化对象过程顺序
* <p>
* 可以任意改变构造对象的顺序,达到不同的效果
**/
public class Director {
private PhoneBuilder phoneBuilder;
public Director(PhoneBuilder phoneBuilder) {
this.phoneBuilder = phoneBuilder;
}
public Phone buildPhone() {
phoneBuilder.buildBrand();
phoneBuilder.buildOs();
phoneBuilder.buildScreen();
return phoneBuilder.createPhone();
}
}
Client 测试类
/**
* @author dynamo2120
* @create 2018-09-28 2:57 PM
* @description
**/
public class Client {
public static void main(String[] args) {
PhoneBuilder applePhoneBuilder = new ApplePhoneBuilder();
Director director1 = new Director(applePhoneBuilder);
Phone applePhone = director1.buildPhone();
System.out.println("applePhone" + applePhone);
PhoneBuilder samSungPhoneBuilder = new SamsungPhoneBuilder();
Director director2 = new Director(samSungPhoneBuilder);
Phone samSungPhone = director2.buildPhone();
System.out.println("samSungPhone" + samSungPhone);
}
}
运行结果
applePhonePhone{brand='Aapple', osPart1='ios part1', osPart2='ios part2', screen='screen1'}
samSungPhonePhone{brand='samsung', osPart1='android part1', osPart2='android part2', screen='screen2'}
使用场景(4)的代码实例
ConnectionProfile 这里仅仅列举了两个属性,实际上是有很多属性的,而且属性在初始化时都不可必填参数
/**
* @author dynamo2120
* @create 2018-07-28 7:16 PM
* @description
*
* 构造对象
*
* 1、常用的就是通过重载构造方法,如果类有很多个属性时会发现构造方法也很多,并且有时候只有几个属性是必须的,也会将其他属性一起初始化
*
* 2、使用set方法进行设置属性,会使用大量的setXXX方法,在某个时刻对象的状态是不一致的,如果在多线程情况下,另外一个线程在修改某个属性时,会产生对象状态不一致
*
* 3、使用建造者模式,在类中定义一个静态内部类Builder,如果是必须传的参数在 构造方法Builder(String name),其他都是可选参数 age(int age) sex(String sex) 这样就更灵活的构建对象
*
*
**/
public class ConnectionProfile {
private String name;
private String desciption;
public ConnectionProfile() {
}
public ConnectionProfile(String name, String desciption) {
this.name = name;
this.desciption = desciption;
}
public static void main(String[] args) {
ConnectionProfile.Builder builder = new ConnectionProfile.Builder("by builder set name").withDescription("by builder set description");
ConnectionProfile connectionProfile = builder.build();
System.out.println("name=" + connectionProfile.getName() + " decription=" + connectionProfile.getDesciption());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesciption() {
return desciption;
}
public void setDesciption(String desciption) {
this.desciption = desciption;
}
public static class Builder {
//里面的属性和ConnectionProfile中的属性相同
private String name;
private String description;
//构建ConnectionProfile对象必须传的参数
public Builder(String name) {
this.name = name;
}
//可选的参数
public Builder withDescription(String description) {
this.description = description;
return this;
}
public ConnectionProfile build() {
return new ConnectionProfile(name, description);
}
}
}
运行结果
name=by builder set name
decription=by builder set description