建造者模式(Builder Pattern)
建造者:需要创建和提供实例,所以是创建型
用户只能看到稳定的接口,后面频繁变动的内容看不到。
所以优点
就是:容易扩展,方便控制风险
由于建造者模式一般通过extends继承或implement实现接口完成。
所以缺点
就是:需要有很多共同点,因此范围有限;易扩展容易出现很多的建造类
注意
: 建造者模式比工厂模式更加关注组装顺序
工厂模式用于处理如何获取实例对象
问题,建造者模式用于处理如何建造实例对象
的问题
理论不再过多赘述,网上很多,这里就贴个图
UML的相关知识,可以访问我的另外一篇博文
注意: 图中是
继承
实现的,而我下面的代码是使用接口
实现的,本质相同。
比较多的一种版本
代码如下:
创建具体的产品
,比如别墅(住房中的一中)相当于这里的Product
,可以理解为一个普通的entity类
public class House {
private String roof; // 房顶
private String wall; // 墙
private String door; // 门
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getDoor() {
return door;
}
public void setDoor(String door) {
this.door = door;
}
@Override
public String toString() {
return "House{" +
"roof='" + roof + '\'' +
", wall='" + wall + '\'' +
", door='" + door + '\'' +
'}';
}
}
接着创建IBuildHouse
,相当于Builder
接口
/**
* @description:
* 具体的产品
*/
public interface IBuildHouse {
void buildRoof();
void buildWall();
void buildDoor();
House createHouse(); // 返回具体的产品
}
接着创建别墅Praetorium
,相当于ConcreteBuilder
,用来实现接口
/**
* @description:
* 具体的建造者,实现接口
*/
public class BuildHouseImpl implements IBuildHouse{
// 引用产品House
private House house;
public BuildHouseImpl() {
house = new House();
}
@Override
public void buildRoof() {
house.setRoof("瓦片");
}
@Override
public void buildWall() {
house.setWall("土块");
}
@Override
public void buildDoor() {
house.setDoor("木头板");
}
@Override
public House createHouse() {
return house;
}
}
频繁变动的地方写完了,最后要写一个稳定的方法来调用频繁变动的方法。
这里使用Director
找建筑队并监督建造别墅。
public class Director {
// 这里传入接口
public House createHouseByDirector(IBuildHouse buildHouse) {
buildHouse.buildWall();
buildHouse.buildDoor();
buildHouse.buildRoof();
// 返回一个House,不能造完连房子都不像
return buildHouse.createHouse();
}
}
测试代码:通过Director监督完成
public static void main(String[] args) {
Director director = new Director();
// new一个具体的产品,这里是我的小别墅规划图
House houseByDirector =
director.createHouseByDirector(new Praetorium());
System.out.println(houseByDirector);
}
扩展方式: 多写几种房子类型继承IBuildHouse
, 就可以实现扩展了。
通过嵌套内部类
的方式实现建造者模式
创建entity类
public class Person {
private Long id;
private String name;
private int age;
private String address;
// 注意:这里个无参构造方法最好为private
// 这样才会通过PersonBuilder创建对象
private Person(){}
// 注意Person 只有get方法,没有set方法
// 所有的赋值操作放在了PersonBuilder中
public Long getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
// 嵌套内部类
public static class PersonBuilder {
Person person;
// 若id,name是必填属性,可以这样编写
// 当创建Person时,必须传入id,name
public PersonBuilder(Long id, String name) {
person = new Person();
person.id = id;
person.name = name;
}
// 若id,name 不是 必填属性,可以注释上面的PersonBuilder()
// 并打开下方的所有注释代码
/* public PersonBuilder() {
person = new Person();
}*/
// 链式调用============================
/* public PersonBuilder id(Long id){
person.id = id;
return this;
}
public PersonBuilder name(String name){
person.name = name;
return this;
}*/
public PersonBuilder age(int age) {
person.age = age;
return this;
}
public PersonBuilder address(String address) {
person.address = address;
return this;
}
// ====================================
// 返回 person,令Builder建造的结果可以用Person接收
// 否则只能返回Person.PersonBuilder
public Person build() {
return person;
}
}
}
测试代码:
public static void main(String[] args) {
// id, name是必填属性
Person person = new Person.PersonBuilder(12L, "lisi")
.address("12345")
.age(123)
.build();
// id, name 不是 必填属性
// Person lisi = new Person.PersonBuilder()
// .address("12345")
// .age(123)
// .name("lisi")
// .build();
System.out.println(person);
}
非常重要
:建造者模式到这就讲完了,如果有心,可以再看一下标题下的文字内容,结合UML图仔细再回味一下建造者模式,相信你可以理解的更深刻,记得更牢固。
代码已经上传到Git:请点击访问
如果大家对于建造者模式还有更多的使用技巧和使用心得,欢迎评论并在评论中分享自己的链接!