建造者模式

介绍

建造者模式又称生成器模式,顾名思义是用来建造或生成某个产品的,当然它与工厂模式的“生成”意义不同。工厂模式并没有考虑产品的生产细节,主要考虑的是多个产品如何生成;而建造者模式主要考虑某个产品具体如何实现,将一个复杂对象的构建与它的表示分离(将产品的创建细节与这个产品的使用分离),使得同样的构建过程可以创建不同的表示

具体实现

角色划分

Builder:生成器接口,定义创建一个Product对象所需的各个部件的操作

ConcreteBuilder:具体的生成器实现,实现各个部件的创建,同时还提供一个让用户获取组装完成后的产品对象的方法

Director:指导者,也被称为导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象

Product:产品,表示被生成器构建的复杂对象,包含多个部件

代码实现

Builder抽象类

public abstract class HouseBuilder {
    protected House house = new House();

    public abstract House buildHead(String head);

    public abstract House buildBody(String body);

    public abstract House buildFoot(String foot);

    public abstract House getHouse();
}

ConcreteBuilder具体建造类

public class CommonHouseBuilder extends HouseBuilder {

    private static final String TAG = "普通";

    @Override
    public House buildHead(String head) {
        house.setHead(TAG + head);
        return house;
    }

    @Override
    public House buildBody(String body) {
        house.setBody(TAG + body);
        return house;
    }

    @Override
    public House buildFoot(String foot) {
        house.setFoot(TAG + foot);
        return house;
    }

    @Override
    public House getHouse() {
        return house;
    }
}
public class VillaHouseBuilder extends HouseBuilder {

    private static final String TAG = "别墅";

    @Override
    public House buildHead(String head) {
        house.setHead(TAG + head);
        return house;
    }

    @Override
    public House buildBody(String body) {
        house.setBody(TAG + body);
        return house;
    }

    @Override
    public House buildFoot(String foot) {
        house.setFoot(TAG + foot);
        return house;
    }

    @Override
    public House getHouse() {
        return house;
    }
}

Director

public class HouseDirector {

    private HouseBuilder builder;

    public void setHouseBuilder(HouseBuilder builder) {
        this.builder = builder;
    }

    public House makeHouse(String head, String body, String foot) {
        this.builder.buildHead(head);
        this.builder.buildBody(body);
        this.builder.buildFoot(foot);
        return this.builder.getHouse();
    }
}

Product

public class House {
    private String head;
    private String body;
    private String foot;

    public String getHead() {
        return head;
    }

    public void setHead(String head) {
        this.head = head;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getFoot() {
        return foot;
    }

    public void setFoot(String foot) {
        this.foot = foot;
    }

    @Override
    public String toString() {
        return "House{" +
                "head='" + head + '\'' +
                ", body='" + body + '\'' +
                ", foot='" + foot + '\'' +
                '}';
    }
}

Client(用于测试的消费者)

public class Client {
    public static void main(String[] args) {
        HouseDirector director = new HouseDirector();
        director.setHouseBuilder(new CommonHouseBuilder());
        House house = director.makeHouse("房顶", "房体", "房基");
        System.out.println(house);

        director.setHouseBuilder(new VillaHouseBuilder());
        house = director.makeHouse("房顶", "房体", "房基");
        System.out.println(house);
    }
}

// 测试结果
// House{head='普通房顶', body='普通房体', foot='普通房基'}
// House{head='别墅房顶', body='别墅房体', foot='别墅房基'}

在这里插入图片描述

主要看实线部分即可

两种房子(普通房子和别墅房)分别由两种建造者生产产品的各部分(head,body,foot),在House类中是没有任何建造细节的,细节都留给builder去实现了,而Director专门负责实现将房子的三个部分拼装到一起

而大多数时候建造一个房子可能并没有这么复杂,或者不需要这么多角色都俱全,那这样写就有些鸡肋了,于是我们是可以对建造者模式进行简化的

  • 去除指导者Director:对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,也就是说组装过程并不是唯一的,可能需要Client自己制定某些步骤,那么干脆去掉“指导者”,把指导者的功能和Client的功能合并起来,也就是说,Client这个时候就相当于指导者,它来指导构建器类去构建需要的复杂对象
  • 去除生成器接口:如果产品是唯一的,只需要创建某个具体的产品,那就没必要加一层抽象builder了

简化建造者模式

甚至直接把Builder作为House静态内部类,这样更为简洁,这种简洁方式在源码中极为常见,很是经典

House产品类

public class House {
    private String head;
    private String body;
    private String foot;

    public House(Builder builder) {
        this.head = builder.head;
        this.body = builder.body;
        this.foot = builder.foot;
    }

    @Override
    public String toString() {
        return "House{" +
                "head='" + head + '\'' +
                ", body='" + body + '\'' +
                ", foot='" + foot + '\'' +
                '}';
    }

    public static class Builder {
        private String head;
        private String body;
        private String foot;

        private static final String TAG = "普通";

        public Builder buildHead(String head) {
            this.head = TAG + head;
            return this;
        }

        public Builder buildBody(String body) {
            this.body = TAG + body;
            return this;
        }

        public Builder buildFoot(String foot) {
            this.foot = TAG + foot;
            return this;
        }

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

Client

public class Test {
    public static void main(String[] args) {
        House house = new House.Builder()
                .buildHead("房顶")
                .buildBody("房体")
                .buildFoot("房基")
                .build();
        System.out.println(house);
    }
}

可能有些读者会有疑问,为何只剩一个Builder了还要写个静态内部类,直接在House类中写建造过程不香吗

那当然是不香了,建造者模式的目的就是将产品使用与产品创建分离,让使用者Client获得House后便不再使用这些方法,即“看不见”这些方法了,这样分离可以将House类的职责显得更为明确,House类的方法只是用来使用它的而不是用来创建它的

建造者模式优点

优点

  • 产品解耦:建造者模式可以用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建的过程独立出来,使得建造过程十分清晰,使它和具体产品的表现松散耦合,从而使得构建算法可以复用,而具体产品表现也可以灵活地、方便地扩展和切换
  • 很容易改变产品的内部表示:由于Builder对象只是提供接口给Director使用,那么具体的部件创建和装配方式是被Builder接口隐藏了的,Director并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换Builder的具体实现即可,不用管Director,因此变得很容易
  • 更好的复用性:生成器模式很好地实现了构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用

选用时机

  • 如果创建对象的算法,应该独立于该对象的组成部分以及它们的装配方式时
  • 如果同一个构建过程有着不同的表示时
源码实践

建造者模式的源码使用有StringBuilder,听名字就知道是个建造者模式,由于StringBuilder的建造过程与产品使用都需要提供给用户决定,所以产品类与Builder类是一个类,这样看StringBuilder其实并不是很符合建造者模式,但设计模式不能一棒子打死嘛,规矩是人定的,改装后的设计更好当然是可以改装的

在我工厂模式博客中工厂模式源码分析举的例子Calendar类也是建造者模式,而且是建造者模式与工厂模式结合

还有一个okhttp3中的Request类就是一个标准的简化建造者模式,与上述的代码如出一辙;再如SqlSessionFactory与SqlSessionFactoryBuilder这一组也是标准的建造者模式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值