Java设计模式:Builder(构建器)模式

基本概念

Builder模式是一步一步创建一个复杂对象的创建型模式。该模式将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。

应用场景

  • 对象创建过程比较复杂,或对创建顺序或组合有依赖(经典Builder模式,可参阅GOF《设计模式》)。
  • 创建对象时所需参数较多,且包含较多可选参数(变种Builder模式,可参阅《Effective Java》构建器小节)。

示例代码

本节侧重变种Builder模式,示例代码如下:

public class RobustPerson {
    // 必要参数
    private final int id; // 所有属性都被final修饰
    private final String name;

    // 可选参数
    private final int age;
    private final String gender;
    private final double height;
    private final int weight;

    private RobustPerson(Builder builder) { // 构造方法私有,即客户端不能直接创建RobustPerson对象
        this.id = builder.id;
        this.name = builder.name;
        this.age = builder.age;
        this.gender = builder.gender;
        this.height = builder.height;
        this.weight = builder.weight;
    }

    public static final class Builder {
        // 必要参数
        private final int id; // 必要属性被final修饰
        private final String name;

        // 可选参数
        private int age;
        private String gender;
        private double height;
        private int weight;

        public Builder(int id, String name) { this.id = id; this.name = name; } // 必要参数通过构造方法赋值

        public Builder age(int age) { this.age = age; return this; } // 可选参数通过同名方法赋值
        public Builder gender(String gender) { this.gender = gender; return this; }
        public Builder height(double height) { this.height = height; return this; }
        public Builder weight(int weight) { this.weight = weight; return this; }

        public RobustPerson build() {
            RobustPerson person = new RobustPerson(this);
            // 复杂业务语义校验,对于校验不通过场景,抛出异常
            if (person.height != 0 && person.weight != 0) { // Builder对象并非线程安全的,不能用this.xxx校验
                double bmi = person.weight / (person.height * person.height);
                if (bmi < 18 || bmi > 25) { // 身体质量指数(BMI)低于18或高于25时表示不健康
                    throw new IllegalArgumentException(person.name+" NOT A ROBUST PERSON!");
                }
            }
            return person;
        }
    }

    public Builder toBuilder() { // 克隆
        return new Builder(this.id, this.name).age(this.age)
                .gender(this.gender).height(this.height).weight(this.weight);
    }

    @Override
    public String toString() {
        return name + "{" + "id=" + id + ", age=" + age + ", gender='" + gender + '\'' +
                ", height=" + height + "m, weight=" + weight + "kg}";
    }
}

测试类如下:

public class BuilderTest {
    public static void main(String[] args) {
        RobustPerson jack = new RobustPerson.Builder(1, "Jack")
                .age(18).gender("male").height(1.70).weight(65).build();
        System.out.println(jack);

        System.out.println("Jack keeps eating too much...");
        System.out.println(jack.toBuilder().weight(80).build());
    }
}

运行后输出:

Jack{id=1, age=18, gender='male', height=1.7m, weight=65kg}
Jack keeps eating too much...
Exception in thread "main" java.lang.IllegalArgumentException: Jack NOT A ROBUST PERSON!
    at builder.RobustPerson$Builder.build(RobustPerson.java:48)
    at builder.BuilderTest.main(BuilderTest.java:14)

关键特点

结合上节示例代码,可知Builder模式创建对象具有以下特点:

  • RobustPerson类的构造方法是私有的,即客户端不能直接创建RobustPerson对象。
  • RobustPerson类不可变(线程安全的): 所有属性都被final修饰,在构造方法中设置参数值,并且不对外提供Setter方法(Getter方法可选)。
  • 静态内部类Builder与RobustPerson拥有相同的成员变量,且Builder内通过构造方法处理final修饰的必要参数,通过同名方法处理可选参数。
  • Builder内的build()方法调用RobustPerson的私有构造函数来创建RobustPerson对象,且客户端只能通过该build()方法创建对象(从而避免Invalid状态)。
  • Builder对象并不具有线程安全性。如果需要对RobustPerson对象的参数强加约束条件,应对build()方法所创建的RobustPerson对象进行检验。
  • 当创建多个对象且对象大多数属性值都相同时,通过toBuilder()可简单高效地克隆对象,仅针对不同的属性重新设置值。
  • Builder模式使用链式调用,可读性更佳。

但Builder模式也不可避免地存在自身的缺点。例如:

  • 创建对象前必须先创建它的构建器,消耗内存(若仅需要链式调用可仿照Builder类定义目标类)。
  • Builder模式存在冗长的样板代码(可借助InnerBuilder或Lombok插件自动生成)。

业界实践

  • StringBuilder(JDK)
  • JobBuilder(quartz-2.3.0.jar)
  • SessionFactoryBuilder等(hibernate-core-5.3.6.Final.jar)

原文地址:https://www.cnblogs.com/clover-toeic/p/11580905.html

时间: 2024-08-29 02:07:23

Java设计模式:Builder(构建器)模式的相关文章

java设计模式之 装饰器模式

适AT java设计模式之 装饰器模式 装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,动态给一个对象添提供了额外的功能. 我们通过下面的实例来演示装饰器模式的用法.模拟一个人从想吃饭.找饭店.享受美食.结束吃饭的过程 代码展示: 首先创建一个被修饰的接口 Eat package deco

设计模式:构建器模式(Builder)

构建器模式有点类似于之前的抽象工厂模式,但比抽象工厂模式更强大,构建器模式可以看做由两部分组成,一是builder,二是director,builder的基本思想就是抽象工厂,而director的存在是为了使得对builder的使用更加灵活,下面是builder的代码示例: class A { public: int i; A() : i(1) {}; }; class B { public: char c; B() : c('a') {}; }; class AB { public: A a;

java设计模式之装饰器模式以及在java中作用

在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用  FilterInputStream和FilterOutputStream 首先,这两个都分别是InputStream和OutputStream的子类.而且,FilterInputStream和FilterOutputStream是具体的子类,实现了InputStream和OutputStream这两个抽象类中为给出实现的方法. 但是,F

java设计模式之七装饰器模式(Decorator)

顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个装饰类,可以为Source类动态的添加一些功能,代码如下: [java] view plaincopy public interface Sourceable { public void method(); } [java] view plaincopy public class Source im

java设计模式之装饰器模式

装饰器模式的应用场景:1.需要扩展一个类的功能.2.动态的为一个对象增加功能,而且还能动态撤销.(继承不能做到这一点,继承的功能是静态的,不能动态增删.) 源接口: 1 public interface Sourceable { 2 3 void method(); 4 } Source类: 1 public class Source implements Sourceable { 2 @Override 3 public void method() { 4 System.out.println

java 设计模式 之 装饰器模式

装饰器模式的作用 在不修改原先对象核心的功能的情况下,对功能进行增强. 增强对象的功能的途径 通过类继承的方式,对父对象进行增强操作,例如造车是父类,改装跑车,跑车加大灯,改装房车,房车加私人电影院.如图: 通过这种方式做的装饰类会因为业务的复杂性激增 2.通过装饰模式,将方法增强.如图 装饰模式架构 car :被装饰的抽象类 package javadesign.decorate; /** * 抽象小汽车 */ public interface Car { public void buildC

浅谈JAVA设计模式之——解析器模式(Interpreter)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45599443 一.概述 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 二.适用性 当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使 用解释器模式.而当存在以下情况时该模式效果最好: 1.该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理. 2.效率不是一个关键问题最高效的解释器通常不是通过直接

设计模式-Builder构建者模式

个人理解 当对象的构造过程变得很复杂的时候,参数很多,通过构造函数会产生大量冗余代码,不好维护,而我们又不希望调用者通过set的方式来构造对象(封装,隐藏),因为这样很容易出问题,于是,可以把整个构造的过程封装在一个构造类里,可以通过构造类实现更加精细的构造,并且职责明确 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不同的表示时. 实现(java)

Java构建器模式

当创建对象需要传入多个参数的时候我们通常会根据参数的数量写不同的构造器,具体如下 public A(int a){} public A(int a, int b){} public A(int a, int b, int c){} 根据不同的参数调用不同的构造器,但是当参数多了的时候,这种方式不够灵活,所以会实现动态传参的方法 public A(){} public void seta(int a){} public void setb(int b){} public void setc(int