建造者(Builder)模式 的若干使用场景

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;    }}

NutritionFacts是不可变的。builder的setter方法返回builder本身,以便可以把调用链接起来。下面就是客户端代码:

NutritionFacts juice = new NutritionFacts.Builder(240, 8).    calories(100).sodium(35).carbohydrate(27).build();

这样的客户端代码很容易编写,跟重要的是,易于阅读。

参考:
1.《大话设计模式》
2.《Effective Java 第二版》

关键字:java, 设计模式, public, int

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部