建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
一般会定义一个公共的抽象建造者,定义了具体需要建造哪些部分;
设置具体的执行者,构建建造过程,顺序等;
定义抽象的公共出的产品对象,提取通用的属性。
实现过程:按需获取或创建对应的具体建造器,执行者执行构造过程,获取生产的结果。
如下:
定义一个建造者:
package cn.pers.sample.build;
/**
* 定义的抽象构建者
* @author WeiSong <br>
* @since 0.0.1
* 2021/1/28 16:59
*/
public abstract class Builder {
protected House house = new House();
abstract void buildBasic();
abstract void buildOut();
abstract void buildInner();
abstract void buildTop();
House getHouse() {
return house;
}
}
定义执行过程:
package cn.pers.sample.build;
/**
* 构建执行过程
*/
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
//产品构建与组装方法
public House construct() {
builder.buildBasic();
builder.buildInner();
builder.buildOut();
builder.buildTop();
return builder.getHouse();
}
}
定义抽象对象:
package cn.pers.sample.build;
import lombok.Data;
/**
* 抽象产品
* @author WeiSong <br>
* @since 0.0.1
* 2021/1/28 16:48
*/
//@Builder
@Data
public class House {
private String basic;
private String out;
private String inner;
private String top;
}
分别构建实现两个具体的建造者:大房子和平房
package cn.pers.sample.build;
/**
* @author WeiSong <br>
* @since 0.0.1
* 2021/1/28 17:04
*/
public class LowHouseBuilder extends Builder {
@Override
void buildBasic() {
house.setBasic("构建平房地基完成");
}
@Override
void buildOut() {
house.setOut("构建平房外立面完成");
}
@Override
void buildInner() {
house.setInner("构建平房装修完成");
}
@Override
void buildTop() {
house.setTop("构建平房顶完成");
}
}
package cn.pers.sample.build;
/**
* @author WeiSong <br>
* @since 0.0.1
* 2021/1/28 17:04
*/
public class TopHouseBuilder extends Builder {
@Override
void buildBasic() {
house.setBasic("构建大房子地基完成");
}
@Override
void buildOut() {
house.setOut("构建大房子外立面完成");
}
@Override
void buildInner() {
house.setInner("构建大房子装修完成");
}
@Override
void buildTop() {
house.setTop("构建大房子顶完成");
}
}
执行最后的生产:
package cn.pers.sample.build;
/**
* @author WeiSong <br>
* @since 0.0.1
* 2021/1/28 17:03
*/
public class MainTest {
public static void main(String[] args) {
//这里具体可以配置 或者反射等方式根据需要获取对应的建造者
Builder builder = new TopHouseBuilder();
Director director = new Director(builder);
final House topHouse = director.construct();
System.out.println(topHouse.toString());
Builder builder1 = new LowHouseBuilder();
Director director1 = new Director(builder1);
final House lowHouse = director1.construct();
System.out.println(lowHouse.toString());
}
}
结果:
House(basic=构建大房子地基完成, out=构建大房子外立面完成, inner=构建大房子装修完成, top=构建大房子顶完成)
House(basic=构建平房地基完成, out=构建平房外立面完成, inner=构建平房装修完成, top=构建平房顶完成)
注意:扩展阅读
代码中 House中有个注释掉的 //@Builder 用过lombok的都知道这个其实就是个构造者模式,我们加上这个注解后看.class的反编译文件
package cn.pers.sample.build;
public class House
{
private String basic;
private String out;
private String inner;
private String top;
House(final String basic, final String out, final String inner, final String top) {
this.basic = basic;
this.out = out;
this.inner = inner;
this.top = top;
}
public static HouseBuilder builder() {
return new HouseBuilder();
}
public String getBasic() {
return this.basic;
}
public String getOut() {
return this.out;
}
public String getInner() {
return this.inner;
}
public String getTop() {
return this.top;
}
public void setBasic(final String basic) {
this.basic = basic;
}
public void setOut(final String out) {
this.out = out;
}
public void setInner(final String inner) {
this.inner = inner;
}
public void setTop(final String top) {
this.top = top;
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof House)) {
return false;
}
final House other = (House)o;
if (!other.canEqual(this)) {
return false;
}
final Object this$basic = this.getBasic();
final Object other$basic = other.getBasic();
Label_0065: {
if (this$basic == null) {
if (other$basic == null) {
break Label_0065;
}
}
else if (this$basic.equals(other$basic)) {
break Label_0065;
}
return false;
}
final Object this$out = this.getOut();
final Object other$out = other.getOut();
Label_0102: {
if (this$out == null) {
if (other$out == null) {
break Label_0102;
}
}
else if (this$out.equals(other$out)) {
break Label_0102;
}
return false;
}
final Object this$inner = this.getInner();
final Object other$inner = other.getInner();
Label_0139: {
if (this$inner == null) {
if (other$inner == null) {
break Label_0139;
}
}
else if (this$inner.equals(other$inner)) {
break Label_0139;
}
return false;
}
final Object this$top = this.getTop();
final Object other$top = other.getTop();
if (this$top == null) {
if (other$top == null) {
return true;
}
}
else if (this$top.equals(other$top)) {
return true;
}
return false;
}
protected boolean canEqual(final Object other) {
return other instanceof House;
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $basic = this.getBasic();
result = result * 59 + (($basic == null) ? 43 : $basic.hashCode());
final Object $out = this.getOut();
result = result * 59 + (($out == null) ? 43 : $out.hashCode());
final Object $inner = this.getInner();
result = result * 59 + (($inner == null) ? 43 : $inner.hashCode());
final Object $top = this.getTop();
result = result * 59 + (($top == null) ? 43 : $top.hashCode());
return result;
}
@Override
public String toString() {
return "House(basic=" + this.getBasic() + ", out=" + this.getOut() + ", inner=" + this.getInner() + ", top=" + this.getTop() + ")";
}
public static class HouseBuilder
{
private String basic;
private String out;
private String inner;
private String top;
HouseBuilder() {
}
public HouseBuilder basic(final String basic) {
this.basic = basic;
return this;
}
public HouseBuilder out(final String out) {
this.out = out;
return this;
}
public HouseBuilder inner(final String inner) {
this.inner = inner;
return this;
}
public HouseBuilder top(final String top) {
this.top = top;
return this;
}
public House build() {
return new House(this.basic, this.out, this.inner, this.top);
}
@Override
public String toString() {
return "House.HouseBuilder(basic=" + this.basic + ", out=" + this.out + ", inner=" + this.inner + ", top=" + this.top + ")";
}
}
}
反编译后查看,里面有个静态类,HouseBuilder ,内部就是一个构建的过程,他和我们这里说的建造者模式是不同的,他是一种以构建的方式来构建对象的过程,可以不对外暴漏set方法,直接以build的方式来构建。比如:House house = House.builder().basic("地基").out("外立面").build();
总结:
1.主要优点
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
(2) 每一个具体建造者没有关联,按需索取具体需要的建造者,即可得到不同的产品对象。
(3) 由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”
(4) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
2.主要缺点
(1) 产品要求具有较多的共同点,其组成部分相似,如果差异性很大,不适合使用建造者模式,比如房子和汽车。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。
3.适用场景
(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。