业务场景
在业务代码中构造了一个类,里面有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); }
不同的家具、房间构成了不同的房子,如果将来业务扩展改动影响也不大
总结
一些基本东西不会变,而其组合经常变化的时候,就适合用建造者模式,特别是很多字段,很多种组合的时候,这种设计结构模型可以把重复的内容抽象
工厂模式和建造者模式的区别
工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对 象,通过设置不同的可选参数,“定制化”地创建不同的对象。