美文网首页程序员
java中的builder模式

java中的builder模式

作者: 刘岳森 | 来源:发表于2017-10-12 19:56 被阅读42次

我们构造一个类常用的有两种方式
一种方式是采用多重载的构造函数,把不同搭配的属性写成不同的构造函数,这种方式的缺点在于代码的重复工作量会非常大,而且用户在用的时候很难分清楚每一种构造函数是干什么的,而且参数顺序输不对可是个大问题,使用起来十分不方便。
另一种方法是通过get,set的方法,这种方法比较容易理解,但是缺点也很明显,一个是参数变量不能是final类型,而且用户不知道什么时候他才能得到一个完整的变量(比方说用户还有很重要的属性没有set就去使用这个变量了)
针对以上的缺点,我们采用builder模式去构建一个新的对象

传统builder模式

图片来自于朱小厮的博客,感谢

传统建造者模式包含四个角色

  • builder(抽象构造者):这个是一个抽象类或者接口,用于抽象具体建造者的函数。
  • ConcreteBuilder(具体建造者):这是抽象构造者的具体实现,实现构造逻辑
  • Director (指导者):可以叫指导者,也可以叫服务员,他不需要知道builder是如何建造产品的,用户直接和指导者进行沟通,指导者有两种操作:告诉builder去建造一个商品;把商品交付给用户
  • Product (产品类):这是我们具体要构造的的对象。

代码

产品类

public class Car
{
    private String wheel;
    private String skeleton;
    private String engine;
// 省略getter和setter方法
}

抽象建造者类

public interface ICarBuilder
{
    public void buildWheel();
    public void buildSkeleton();
    public void buildEngine();

    Car buildCar();
}

具体建造者类

public class ConcreteBuilder implements ICarBuilder
{
    Car car;

    public ConcreteBuilder()
    {
        car = new Car();
    }

    @Override
    public ConcreteBuilder buildWheel()
    {
        car.setWheel("轮子");
    }

    @Override
    public ConcreteBuilder buildSkeleton()
    {
        car.setSkeleton("车身结构");
    }

    @Override
    public ConcreteBuilder buildEngine()
    {
        car.setEngine("发动机");
    }
//前面那些builder方法返回的都是builder,只有当调用下面的build方法的时候才最终构建出了该对象
    @Override
    public Car buildCar()
    {
        return this.car;
    }
}
public class CarDirector
{
    public Car constructCar(ICarBuilder builder)
    {
        builder.buildEngine();
        builder.buildSkeleton();
        builder.buildWheel();
        return builder.buildCar();
    }
}
public class MainTest
{
    public static void main(String[] args)
    {
        CarDirector director = new CarDirector();//在使用的时候先声明中间的服务员,也就是指导者
        Car car = director.constructCar(new ConcreteBuilder());//通过指导者把车构建出来
        System.out.println(car.getWheel());
        System.out.println(car.getEngine());
        System.out.println(car.getSkeleton());
    }
}

此段代码作者朱小厮 原文:https://blog.csdn.net/u013256816/article/details/50978024?utm_source=copy
主要优点是

  • 在建造过程中对象是未生成的,最后调用build方法之后才会生成该对象
  • 有一个builder的interface,扩展性更强,并且可以把build过程与交付给用户的过程解耦开,使用更灵活,封装性好
  • 而且这也形成了漂亮的链式调用
Person person = new Person.PersonBuilder("cj")
                .age(24)
                .job("java")
                .location("苏州")
                .builder();

变种builder模式

在上面的builder模式中,优点显而易见,可扩展性强,但是造成的结果是代码冗余量大,凭空多了三个类,而且并不是所有的情况都需要多个不同实现的builder的,变种builder模式的主要目的是减少多余类的创建,省略了builder抽象类和指导者。

代码

这里主要结合OKHttp源码讲解

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final RequestBody body;
  final Object tag;

  private volatile CacheControl cacheControl; // Lazily initialized.

  Request(Builder builder) {
    //构造函数,省略属性赋值操作
  }

  public Builder newBuilder() {//这里读者可以思考一下为什么会有一个newbuilder模式呢
    return new Builder(this);
  }
//省略部分代码
  public static class Builder {
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;
    Object tag;
//省略部分代码
    Builder(Request request) {//这里读者可以想一想为什么在builder中会有这样一个构造方法,既然我们在创造builder的时候request是空的,那我们什么时候会用到这个方法呢?
      //构造函数,省略属性赋值操作
    }
//省略部分代码
     public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
         return new Request(this);
    }
}

在变种builder模式中,直接将指挥者和抽象builder类去掉了,取而代之的是静态内部类builder,牺牲了一部分的可扩展性,将代码逻辑大大简化。

感谢原作者
这种builder的作用和传统builder是一样的
这个时候有一个问题,当我的对象属性相当多,而且我现在要新建一个对象,这个对象的属性值只有一两个和我已有的对象不同,这个时候我要怎么做?
粘贴上一段代码?重新输入?
毕竟builder模式创建的对象一但创建成功里面的属性就不能再修改,所以拷贝一个对象再更改属性的方法是不可行的
我在一开始读OKhttp的源码的时候也很好奇它里面为什么会有一个newBuilder方法,builder中会有一个参数为request的构造方法,这里不得不惊叹设计者的强大,原文在此
public Builder newBuilder() {
    return new Builder(this);
  }

这里通过原有的request的newBuilder方法生成一个新的,并且属性值和request一样的builder,之后再用这个新的builder更改属性后生成新的request。


3a1e797ababcd9d1a2c7f031a6670ad7.png

巧妙地通过产品构造出builder,更改builder产生全新的产品。通过逆向构造的过程完成了整个拷贝

对比传统builder模式和变种builder模式

传统的builder模式优点是可扩展性强,但是同时缺点是要创造4个类,对于初学者很不友好,而且代码冗余量大,变种builder使用更加便捷,操作更加方便

相关文章

  • 11.2设计模式-构建者模式-详解

    构建者模式 java的builder模式详解 builder模式在android中的实际运用 1.java的bui...

  • Java设计模式教程

    Java设计模式教程 Java工厂设计模式 Java抽象工厂模式 Java单例模式 Java建造者(Builder...

  • 设计模式:Builder

    Builder模式基本介绍Builder模式的实现源码中的Builder模式记录 Builder模式基本介绍 Bu...

  • java中的builder模式

    我们构造一个类常用的有两种方式一种方式是采用多重载的构造函数,把不同搭配的属性写成不同的构造函数,这种方式的缺点在...

  • Java builder 模式

    Java builder 模式 在Java builder模型中有两个实体对象: 实体对象 实体对象对应的Buil...

  • 设计模式:创造型

    工厂方法 抽象工厂 单例 构建者模式:Android中的Dialog.builder 原型模式:java中的clo...

  • Java设计模式之03_Builder(建造者模式)

    更多Java设计模式:Java设计模式-目录 建造者模式(Builder Pattern)使用多个简单的对象一步一...

  • java中的Builder设计模式

    前言 很久前就看到过这种“神奇的”构造器模式,但是一直没有深究,直到最近再使用 OKHTTP 的时候才发现这种用法...

  • Builder模式创建实例

    在java中实例化一个类的对象一般有三种模式,重叠构造器模式,javabean模式,builder模式。 重叠构造...

  • Java Builder模式

    Builder模式的作用是将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。它可以不直接生成想...

网友评论

    本文标题:java中的builder模式

    本文链接:https://www.haomeiwen.com/subject/ogboyxtx.html