1.场景一
如果我们需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们可以使用 Builder模式,又叫生成器模式。如果我们用了Builder模式,那么用户就只需要指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。
比如现在我们有一个这样的使用场景,需要在屏幕上画小人,人要有头手脚,要画不同的人,胖的小人,瘦的小人,矮的小人。按照通常的写法,会有很多的样板代码,画人的头,画人脚手,如果一不小心,非常容易缺胳膊少腿。
下面我们演示Builder模式的实现:public class Person { //限于篇幅get和set方法此处省略 Head head; Body body; Arm leftArm; Arm rightArm; Leg leftLeg; Leg rightLeg; public void drawHead(int size){...} public void drawBody(int size){...} public void drawLeftArm(int size){...} public void drawRightArm(int size){...} public void drawLeftLeg(int size){...} public void drawRightLeg(int size){...} } abstract class BuilderPerson { protected Person person = new Person(); public abstract void buildHead(); public abstract void buildBody(); public abstract void buildLeftArm(); public abstract void buildRightArm(); public abstract void buildLeftLeg(); public abstract void buildRightLeg(); } public class BuilderThinPerson extends BuilderPerson{ @Override public void buildHead() { person.drawHead(10); } @Override public void buildBody() { person.drawBody(10); //画胖小人只需将这边的数值修改, // 再生成一个类即可 } @Override public void buildLeftArm() { person.drawLeftArm(5); } @Override public void buildRightArm() { person.drawRightArm(5); } @Override public void buildLeftLeg() { person.drawLeftLeg(7); } @Override public void buildRightLeg() { person.drawRightLeg(7); } } 我们还缺Builder模式中一个非常重要的类,指挥者(Director),用它来控制建造过程,也用来隔离用户与建造过程的关联。 public class PersonDirector{ private BuilderPerson pb; public PersonDirector(BuilderPerson pb){ this.pb = pb; } //建造的过程在指挥者这里完成,用户就不需要知道了 public void createPerson() { pb.buildHead(); pb.buildBody(); pb.buildLeftArm(); pb.buildRightArm(); pb.buildLeftLeg(); pb.buildRightLeg(); } } 客户端代码 BuilderPerson bp = new BuilderThinPerson(); PersonDirector pd = new PersonDirector(bp); pd.createPerson();
2.场景二
遇到多个构造器参数时要考虑用构建器。静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。
考虑这样的一个场景:用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个域是必需的:每份的含量、每罐的含量以及每份的卡路里,还有超过20个可选域:总脂肪量、饱和脂肪量、转化脂肪、胆固醇、钠等等。
程序员一向习惯采用重叠构造器模式,在这种模式下,你提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有可选参数。重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然难以阅读。一长串类型相同的参数会导致一些微妙的错误。如果客户端不小心颠倒了其中两个参数的顺序,编译器也不会出错,但是程序在运行时会出现错误的行为。
下面是Builder模式的代码:public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public static class Builder { //required parameters private final int servingSize; private final int servings; //Optional parameters - initialized to default values private int calories; private int fat; private int sodium; private int carbohydrate; public Builder(int servingSize, int servings){ this.servingSize = servingSize; this.servings = servings } public Builder calories(int val){ calories = val; return this; } public Builder fat(int val){ fat = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public Builder carbohydrate(int val){ carbohydrate = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder){ servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } }