Java链式构造器(译)

我们写代码时,随时都要创建对象。 通常我们使用new关键字创建对象,这就涉及调用构造函数来初始化我们的对象。

假设我们有一个描述耳机的类,当中有两个属性:颜色和价格,默认的情况下,耳机是黑色的,售价150美元,于是我们有了以下代码

public class Headphones {
    private final Color color;
    private final BigDecimal priceInDollars;
    public Headphones() {
        this.color = Color.BLACK;
        this.priceInDollars = BigDecimal.valueOf(150.0);
    }
    //other methods
}

一段时间后,我们决定制作不同颜色的耳机了,但是价格维持不变,对于这种情况,我们增加了一个新的构造函数:价格设置为默认值,但颜色通过参数传入构造方法:

public Headphones(final Color color) {
    this.color = color;
    this.priceInDollars = BigDecimal.valueOf(150.0);
}

再过一段时间后,我们决定不同颜色的耳机可以有不同的价格。 于是我们再次添加了一个新的构造函数:

public class Headphones {
    private final Color color;
    private final BigDecimal priceInDollars;
    public Headphones() {
        this.color = Color.BLACK;
        this.priceInDollars = BigDecimal.valueOf(150.0);
    }
    public Headphones(final Color color) {
        this.color = color;
        this.priceInDollars = BigDecimal.valueOf(150.0);
    }
    public Headphones(final Color color, final BigDecimal priceInDollars) {
        this.color = color;
        this.priceInDollars = priceInDollars;
    }
    //other methods
}

我们可以看到,以上的实现导致编码重复。 每个构造函数都必须自己设置所有字段,如果我们想要更改默认值,我们必须改变所有构造函数。 那我们该怎么做呢?

想到的第一个解决方案是我们可以使用默认值:

public class Headphones {
    private Color color = Color.BLACK;
    private BigDecimal priceInDollars = BigDecimal.valueOf(150.0);
    public Headphones() {
    }
    public Headphones(final Color color) {
        this.color = color;
    }
    public Headphones(final Color color, final BigDecimal priceInDollars) {
        this.color = color;
        this.priceInDollars = priceInDollars;
    }
    //other methods
}

现在,我们的构造函数只设置他们想要更改的字段。

我们也可以用另一种方式完成它并使用初始化程序设置默认值:

public class Headphones {
    private Color color;
    private BigDecimal priceInDollars;
    {
        this.color = Color.BLACK;
        this.priceInDollars = BigDecimal.valueOf(150.0);
    }
    //other
}

当然,这三种方式可以混合使用。 你可以通过构造函数设置一个字段,通过默认值设置第二个字段,并在初始化程序中设置第三个字段,但有什么好处呢?

我没有看到任何好处,反而发现很多问题:

  • 我们没有一个统一的实现, 每个构造方法的实现都完全独立。

  • 不够简洁,由于有多个实现,使用者需要关心每一个实现

  • After transformation, our fields cannot be final. We are setting default values regardless of whether we change them or not, so we have to make the possibility of changing it

  • Unnecessary field initialization is creating an unused object. This is not really a problem until you are creating millions of objects

我们怎么解决这些问题呢?

答案是使用链式构造器。

链式构造器意味着我们以一种方式编写构造函数,构造函数调用其他构造函数,最终到达统一的构造函数。 这个统一的构造函数称为主构造函数,所有其他构造函数称为辅助构造函数。

主构造函数将是我们创建和初始化对象的单一点,因此我们可以将所有常见行为放入其中。 为了保持一致性,我们只有一个主要的构造函数; 理想情况下,此构造函数将设置所有类字段。 此外,重要的是,如果我们不想对外公开主构造函数,那么主构造函数可以设置成私有的。

使用链式构造器,你不必担心代码重复。 因此,它将使你的代码更简单,更易于维护。 所有构造函数最终都调用主构造函数,这是一个可以共享公共代码的单点创建。

我建议你将主构造函数编写为类中的最后一个构造函数,并将其作为所有辅助函数编写,就像我在下面的Headphones所做的那样:

public class Headphones {
    private final Color color;
    private final BigDecimal priceInDollars;
    public Headphones() {
        this(Color.BLACK);
    }
    public Headphones(final Color color) {
        this(color, BigDecimal.valueOf(150.0));
    }
    public Headphones(final Color color, final BigDecimal priceInDollars) {
        this.color = color;
        this.priceInDollars = priceInDollars;
    }
    //other methods
}

尽管Java提供了不同的方式实现初始化,我的建议是

  • 永远不要使用初始化程序块,永远不要使用默认值初始化成员,始终链接构造函数。

在创建类时,请始终考虑如何正确设计它。 公开许多构造函数将提供不同的创建方式,从而增加代码的可用性。

设计类不仅意味着提供一个易单漂亮的API,而且还意味着保持所有代码内部的可维护性和可读性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,739评论 2 9
  • 深夜24点,看资料看不进去,白天茶水灌太多睡不着,加之下午受到感情挫伤,又来这里闲言碎语。 好久都没有出去走走看看...
    Ami小米阅读 303评论 1 0
  • 有一丝烦躁,明明什么都想依靠自己,却什么都不能自已; 有一丝烦躁,大家都在为未来奋斗拼搏时,我却看不清自己的未来;...
    瑜儿么么哒阅读 227评论 0 0
  • 关于作者 泰·田代是美国马里兰大学情感、性格以及成瘾症研究中心的资深研究员,探索传播公司旗下美体健康频道的情感专家...
    西门胖子阅读 545评论 0 0