建造者模式
业务场景
在业务代码中构造了一个类,里面有7个字段,需要给构造方法传7个值
public class Home {
//门
private String Door;
//椅子
private String Chair;
//厨房
private String Kitchen;
//马桶
private String Toilet;
//浴室
private String Bathroom;
//书房
private String Study;
//游泳池
private String SwimmingPoor;
public void setDoor(String door) {
Door = door;
}
public void setChair(String chair) {
Chair = chair;
}
public void setKitchen(String kitchen) {
Kitchen = kitchen;
}
public void setToilet(String toilet) {
Toilet = toilet;
}
public void setBathroom(String bathroom) {
Bathroom = bathroom;
}
public void setStudy(String study) {
Study = study;
}
public void setSwimmingPoor(String swimmingPoor) {
SwimmingPoor = swimmingPoor;
}
public Home(String door, String chair, String kitchen, String toilet, String bathroom, String study, String swimmingPoor) {
Door = door;
Chair = chair;
Kitchen = kitchen;
Toilet = toilet;
Bathroom = bathroom;
Study = study;
SwimmingPoor = swimmingPoor;
}
public Home() {
}
}
因为需要建房子,当时我们的类后面经过扩展发展到了15个字段,甚至更多
private String Door;//门
private String Chair; //椅子
private String Kitchen; //厨房
private String Toilet; //马桶
private String Bathroom; //浴室
private String Study; //书房
private String SwimmingPoor; //游泳池
.........
那继续沿用现在的设计思路,构造函数的参数列表会变得很长,代码在可读性和易用性上都会变差。在使用构造函数的时候,我们就容易搞错各参数的顺序,传递进错误的参数值,导致非常隐蔽的 bug。
Home home=new Home("铁门","摇摇椅","厨房","","",......)
于是乎可能想到使用set方法来解决,可以选择填写或者不填写
Home home=new Home();
home.setBathroom("玻璃浴室");
home.setChair("木椅子");
home.setDoor("防盗门");
home.setStudy("书房");
home.setToilet("");
home.set....
但问题又来了,如果我们的构造方法需要进行扩展,比如建有的类型的房子,有的参数不需要使用了,又编写新的构造方法,一个参数依赖另外两个参数,比如我设置了房间的大小,长宽这两个属性是互相依赖的。
public Home(String door, String chair, String kitchen,String width,String height)
{
Door = door;
Chair = chair;
Kitchen = kitchen;
Width=width;
Height=height;
}
这样很好,可是如果我们参数就是随意更改和搭配的,那么每次都需要我重新编写构造参数,这样还将细节对外暴露了。单纯用构造函数或者set方法无法做到对参数进行约束,对象可能还存在空或者无效。
建造者模式重构
例如上面,有很多参数需要我们去搭配修改,用来创建不同的对象方法
就像建房子,我们不需要去建,只需要把我们的需求告诉建造者,让它去创建,最后我只管得到这个房子去验收。
建造者接口
public interface IHome {
IHome Door(String door);//桌子
IHome Chair(String chair); //椅子
IHome Kitchen(String kitchen); //厨房
IHome Toilet(String toilet); //马桶
IHome Bathroom(String bathroom); //浴室
String getDetail();//详细信息
}
具体实现的建造者
public class HomeBuilder implements IHome {
Home home=new Home();
List<String> list=new ArrayList<>();
@Override
public IHome Door(String door) {
home.setDoor(door);
list.add(door);
return this;
}
@Override
public IHome Chair(String chair) {
home.setChair(chair);
list.add(chair);
return this;
}
@Override
public IHome Kitchen(String kitchen) {
home.setKitchen(kitchen);
list.add(kitchen);
return this;
}
@Override
public IHome Toilet(String toilet) {
home.setToilet(toilet);
list.add(toilet);
return this;
}
@Override
public IHome Bathroom(String bathroom) {
home.setBathroom(bathroom);
list.add(bathroom);
return this;
}
@Override
public String getDetail() {
StringBuilder detail = new StringBuilder();
for (String s : list) {
detail.append(s+" ");
}
return detail.toString();
}
}
建造者方法
public class Build {
//普通出租房
public IHome leveZero() {
return new HomeBuilder().Chair("塑料椅").Door("塑料门").Kitchen("小厨房");
}
//红木家庭房子
public IHome leveOne() {
return new HomeBuilder().Chair("红木椅").Bathroom("浴室").Door("红木门");
}
//欧式家庭房子
public IHome leveTwo() {
return new HomeBuilder().Chair("北欧ins椅").Bathroom("露天浴室").Door("北欧ins门").Kitchen("北欧厨房");
}
}
测试验证
public void test()
{
Build build=new Build();
String detail = build.leveOne().getDetail();
System.out.println(detail);
String detail2 = build.leveZero().getDetail();
System.out.println(detail2);
}
不同的家具、房间构成了不同的房子,如果将来业务扩展改动影响也不大
总结
一些基本东西不会变,而其组合经常变化的时候,就适合用建造者模式,特别是很多字段,很多种组合的时候,这种设计结构模型可以把重复的内容抽象
工厂模式和建造者模式的区别
工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对 象,通过设置不同的可选参数,“定制化”地创建不同的对象。