在新建对象时,若需要对大量可选参数进行赋值,最常见的做法是JavaBeans模式,即调用一个无参构造方法创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。代码示例如下:

public class Complex {
    private int size;
    private int color;
    private int range = 0;
    private int num = 0;

    public Complex(int size, int color) {
        this.size = size;
        this.color = color;
    }

    public void setRange(int range) {
        this.range = range;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

这种模式需要的代码语句繁琐,而且这种做法阻止了把类做成不可变的可能。更加简洁的一种方式是通过多个构造方法去新建对象。比如下面的代码:

public class Complex {
    private int size;
    private int color;
    private int range = 0;
    private int num = 0;

    public Complex(int size, int color) {
        this.size = size;
        this.color = color;
    }

    public Complex(int size, int color, int range) {
        this.size = size;
        this.color = color;
        this.range = range;
    }

    // public Complex(int size, int color, int num) {
    //     this.size = size;
    //     this.color = color;
    //     this.num = num;
    // }

    public Complex(int size, int color, int range, int num) {
        this.size = size;
        this.color = color;
        this.range = range;
        this.num = num;
    }

}

当参数越来越多时,这种方式就会使类的结构变得臃肿,难以维护,在使用时也需要去逐个理解每种构造方法的参数意义。并且在上述示例中,也是无法打开被注释掉的构造方法。

有没有一种更好的创建大量可选参数对象的方式?答案是Builder模式。先来看下面的示例代码:

public class NutritionFacts {
    private final int size;
    private final int color;
    private final int num;
    private final int range;

    public static class Builder {
        private int size;
        private int color;
        private int range = 0;
        private int num = 0;

        public Builder(int size, int color) {
            this.size = size;
            this.color = color;
        }

        public Builder num(int num) {
            this.num = num;
            return this;
        }

        public Builder range(int range) {
            this.range = range;
            return this;
        }

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

    private NutritionFacts(Builder builder) {
        this.color = builder.color;
        this.num = builder.num;
        this.size = builder.size;
        this.range = builder.range;
    }

    public static void main(String[] args) {
        NutritionFacts build = new NutritionFacts.Builder(2, 1)
                .num(3).range(4).build();
    }
}

通过观察示例代码,不难发现。这种模式的本质是不直接生成想要的对象,而是通过链式编程构建一个参数完备的构造器对象,最终通过调用构造器对象的build()方法来生成不可变的目标对象。

显而易见,链式编程的秘诀在于从实例化对象开始,每次调用成员方法都会返回自身对象。

写到这里,笔者打算扩展下内部类与静态内部类的相关知识。

内部类与静态内部类

观察下面的静态内部类的声明,static关键字位于class关键字之前(顺序颠倒会报错),说明static的规则优先于class的规则。理解了这一点,就不难理解如何使用静态内部类。

public class InnerClass {

    public class Inner{
        public Inner(){
            //..
        }
    }

    public static class StaticInner{
        static int i = 10;
        public StaticInner(){
            //..
        }
    }

}

对于内部类的实例化:

因为内部类属于外部类的非静态成员,所以首先需要实例化外部类,其次因为内部类也属于类,使用之前故也需要实例化。

    public static void main(String[] args) {

        new InnerClass().new Inner();

    }

对于静态内部类的实例化:

因为static关键字必须声明在class之前,所以可知static的规则优先于class的规则。在处理类的静态成员时,优先使用“类名.静态成员”的形式,其次,再考虑实例化或其它变量引用。

    public static void main(String[] args) {

        new InnerClass.StaticInner();

        int i = InnerClass.StaticInner.i;
    }

本文参考资料:《Effective Java》

使用Builder模式创建复杂可选参数对象的更多相关文章

  1. Android 开发学习进程0.30 builder模式创建popwindow

    builder模式创建自定义popwindow builder设计模式 将一个复杂的对象构建与它的表示分离,简化代码的使用方式.当对象有多个参数或多个零件同时初始化方法同时初始化方法有默认值时,采用此 ...

  2. effective java 3th item2:考虑 builder 模式,当构造器参数过多的时候

    yiaz 读书笔记,翻译于 effective java 3th 英文版,可能有些地方有错误.欢迎指正. 静态工厂方法和构造器都有一个限制:当有许多参数的时候,它们不能很好的扩展. 比如试想下如下场景 ...

  3. java Builder模式创建不可变类

    package com.geostar.gfstack.operationcenter.logger.manager.common; /** * Created by Nihaorz on 2017/ ...

  4. 02.当构造参数过多时使用builder模式

    前言 <Effective Java>中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看.其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文<给Java程序猿们 ...

  5. 【转】设计模式(三)建造者模式Builder(创建型)

    (http://blog.csdn.net/hguisu/article/details/7518060) 1. 概述 在软件开发的过程中,当遇到一个"复杂的对象"的创建工作,该对 ...

  6. 设计模式(二): BUILDER生成器模式 -- 创建型模式

    1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式 ...

  7. 设计模式(三)建造者模式Builder(创建型)

    1. 概述 在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定 ...

  8. 设计模式之建造者模式Builder(创建型)

    1. 概述 在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定 ...

  9. Builder模式在Java中的应用

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

随机推荐

  1. 关于Layer ui的加载层位置居中问题

    最近在项目中一直使用layerui的相应的提示框以及它的加载层,然而就在今天遇到了一个神奇的问题,我使用 var index = layer.load(0, {shade: false}); 结果一直 ...

  2. CAS机制与自旋锁

    CAS(Compare-and-Swap),即比较并替换,java并发包中许多Atomic的类的底层原理都是CAS. 它的功能是判断内存中某个地址的值是否为预期值,如果是就改变成新值,整个过程具有原子 ...

  3. RecyclerSwipeAdapterDemo【使用AndroidSwipeLayout用于列表项侧滑功能】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 记录AndroidSwipeLayout搭配Recyclerview实现列表项侧滑功能. 效果图 代码分析 适配器类中设置Swipe ...

  4. Spring Boot系列(一) Spring Boot准备知识

    本文是学习 Spring Boot 的一些准备知识. Spring Web MVC Spring Web MVC 的两个Context 如下图所示, 基于 Servlet 的 Spring Web M ...

  5. 4.2WebHost配置「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. WebHost配置 覆盖配置文件和修改启动URL 覆盖配置文件和修改启动URL是经常使用的地方,覆盖配置文件可以自 ...

  6. c++性能测试工具:google benchmark入门(一)

    如果你正在寻找一款c++性能测试工具,那么这篇文章是不容错过的. 市面上的benchmark工具或多或少存在一些使用上的不便,那么是否存在一个使用简便又功能强大的性能测试工具呢?答案是google/b ...

  7. RequireJS入门级_RequireJS能给我们带来什么帮助?

    前言:其实很早前就已经接触和了解到RequireJS了,当时只是大概明白它能用来控制JS的加载顺序,即:页面一定要先加载这个JS,再加载那个JS,对于RequireJS的好处还没有一个真正的体会和认识 ...

  8. 10分钟 在linux里创建.net core helloworld控制台程序

    官方教程 安装linux https://www.cnblogs.com/LittleFeiHu/p/9749455.html 第一步 :选择和你本机适用的Linux版本,我这里用的是18.04. 第 ...

  9. 第三章:shiro授权认证

    授权:也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等). 主体:即访问应用的用户,在Shiro中使用Subject代表该用户.用户只有授权后才允许访问相应的资源. 资源 ...

  10. CDN的简单理解

    百度百科上的解释:CDN的全称是Content Delivery Network,即内容分发网络.CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡.内容分发.调 ...