设计模式(二)-构建者模式

定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。

定义很简短理解起来不是那么直观,我们使用汽车生产的例子来解释一下。一辆汽车它有很多零件拼装而成,例如引擎、底盘、变速箱、轮胎等等许多零件,而如何将这些零件拼装成一辆汽车出来这就是构建者模式需要解决的问题。构建者模式是一种较为复杂且使用频率并不是那么高的创建者模式,通常情况下构建者模式为客户端创建的对象都不是一个简单的对象。

代码实现

在传统的构建者模式中通常包含以下四种对象:

抽象构建者

它为创建一个产品对象的各个部件指定抽象接口,在该接口中一般含有两种方法。一种是用于创建复杂对象的各个部件的方法,另外一种则是返回复杂对象方法。

例如在创建汽车这个场景中,我们定义的抽象构建者代码如下所示:

public abstract class CarBuilder {

    protected Car car = new Car();

    /**
     * 构建引擎
     */

    public abstract void buildEngine();

    /**
     * 构建底盘
     */

    public abstract void buildChassis();

    /**
     * 构建变速箱
     */

    public abstract void buildGearbox();

    /**
     * 构建轮胎
     */

    public abstract void buildTire();

    public Car getResult(){
        return car;
    }
}
具体创建者

它是抽象构建者的实现者,在它的内部实现了各个组件的具体构造和装配方法,定义并明确它所创建的复杂对象。

例如在我们的例子中,我们有两种构建者用来构建家用车和SUV。

public class FamilyCarBuilder extends CarBuilder{

    @Override
    public void buildEngine() {
        car.setEngine("省油的引擎");
    }

    @Override
    public void buildChassis() {
        car.setChassis("表现均衡的底盘");
    }

    @Override
    public void buildGearbox() {
        car.setGearbox("没有特点的变速箱");
    }

    @Override
    public void buildTire() {
        car.setTire("偏舒适性的轮胎");
    }
}

public class SUVBuilder extends CarBuilder {

    @Override
    public void buildEngine() {
        car.setEngine("大马力引擎");
    }

    @Override
    public void buildChassis() {
        car.setChassis("比较高的底盘");
    }

    @Override
    public void buildGearbox() {
        car.setGearbox("耐用的变速器");
    }

    @Override
    public void buildTire() {
        car.setTire("抓地力好的轮胎");
    }
}
产品角色

就是我们想构建的复杂对象。在我们的示例中就是汽车。

public class Car {
    /**
     * 引擎
     */

    private String engine;
    /**
     * 底盘
     */

    private String chassis;
    /**
     * 变速箱
     */

    private String gearbox;
    /**
     * 轮胎
     */

    private String tire;
    //省略getter和setter等方法
}
指挥者

该角色负责安排复杂对象的构建次序,指挥者与抽象构建者之间存在关联关系。一般在构建对象的方法中调用构建者对象的部件构造与装配方法完成复杂对象的构建,而客户端一般只需要与指挥者进行确定构建者的类型即可。

public class Director {

    private CarBuilder builder;

    public Director(CarBuilder builder) {
        this.builder = builder;
    }

    public Car build(){
        builder.buildEngine();
        builder.buildChassis();
        builder.buildGearbox();
        builder.buildTire();
        return builder.getResult();
    }

    public void setBuilder(CarBuilder builder) {
        this.builder = builder;
    }
}

客户端调用代码

通过上面四种角色的介绍与代码示例,在客户端我们便可以很轻松的构建出家用车和SUV对象。

public class App {
    public static void main(String[] args) {
        //家用车
        CarBuilder builder = new FamilyCarBuilder();
        Director director = new Director(builder);
        Car car = director.build();
        System.out.println(car);
        //SUV
        builder = new SUVBuilder();
        director.setBuilder(builder);
        car = director.build();
        System.out.println(car);
    }
}

Lombok中的构建者模式

前面所说的是传统的构建者模式,但在实际应用中构建者模式并非固定,构建者模式主要的特点就是用来分离对象属性与创建。如果使用过Java中的Lombok就知道我们可以使用@Builder来实现构建者模式。那么Lombok是如何实现的呢?

public class User {
    private String name;
    private Integer age;
    private String sex;

    public User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.sex = builder.sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", sex='" + sex + ''' +
                '}';
    }

    private static class Builder{
        private String name;
        private Integer age;
        private String sex;

        public Builder() {
        }

        public Builder name(String name){
            this.name = name;
            return this;
        }

        public Builder age(Integer age){
            this.age = age;
            return this;
        }

        public Builder sex(String sex){
            this.sex = sex;
            return this;
        }

        public User build(){
            return new User(this);
        }
    }

    public static void main(String[] args) {
        User mac = User mac = new User.Builder().name("mac").age(18).sex("man").build();
        System.out.println(mac);
    }
}

上面代码我们实现了@Builder一模一样的效果,如果你使用过Lombok查看反编译后的代码可以发现,反编译后的代码与我们所写的代码基本上类似。从代码层面上来说,客户端创建对象时变得更加清晰明了,但我们自己手动来写还是比较麻烦的,特别是在属性较多的情况下,所以还是比较推荐使用Lombok来完成。

总结

构建者模式这种设计,优缺点还是比较明显的。从优点上来说:

  • 对客户端隐藏了复杂对象的构建过程,将对象的创建与对象本身进行了解耦,使得相同的创建过程可以创建不同的产品对象。
  • 每一个具体创建者都相对独立,与其他具体创建者之间并没有依赖关联,所以在更换具体创建者或者新增具体创建者时不需要修改原先的代码,符合开闭原则。
  • 可以精确把控产品创建的过程。

而它的缺点也相对明显:

  • 如果所创建的产品之间有较大的差异,例如很多组成部件都不相同则不太适合使用构建者模式。
  • 如果产品内部的变化很复杂可能会导致具体创建者的数量增多。

本文示例代码地址:https://gitee.com/zengchao_workspace/design-pattern


原文始发于微信公众号(一只菜鸟程序员):设计模式(二)-构建者模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72900.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!