第1条:考虑用静态工厂方法代替构造器

通常情况下,我们创建一个对象采取new的形式,但是还有一种方法也是经常使用到的,它的名称叫做静态工厂方法。

例如,java中基本类型boolean的包装类Boolean就采用了这种方式,源代码如下:

    public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

当然,除了valueOf这种比较low的名字之外,我们常用的还有getInstance(最常见),newInstance,getType等。

静态工厂方法相对于构造器,好处多多。

①静态工厂方法有名称,而构造器是固定的。

例如,BigInteger的构造方法返回一个数字。如果想返回一个随机素数,用名为BigInteger.probablePrime的静态方法表示显然会更加清晰易读。

②不必每次调用的时候都创建一个新的对象。

这使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来重复利用,从而避免创建不必要的重复对象。例如上例中的Boolean.valueOf(boolean b)方法,调用它时,它从来没有创建对象。

③它可以返回原返回类型的任何子类型对象。

这里就不得不提及以下简单工厂模式,大家在平时开发中使用频率极高。

例如,有物理型英雄和法术型英雄,想要根据传入的类型获取对应的英雄。

public abstract class Hero {
} public class APHero extends Hero {
@Override
public String toString() {
return "法术型英雄";
}
} public class ADHero extends Hero {
@Override
public String toString() {
return "物理型英雄";
}
}

使用静态工厂方法就可以获取到指定的子类型,大大增加了可扩展性。

public class HeroFactory {
APHero ap = new APHero();
ADHero ad = new ADHero();
public Hero getHeroInstance(String type){
switch(type){
case "AP":return ap;
case "AD":return ad;
default: return null;
}
}
}

第2条:遇到多个构造器参数时考虑用构建器

静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。

有时候会碰到这样的情况,一个类里面属性很多,有些是必须的,有些是可选的。这样一来,普通的构造方法就得写一大堆(因为创建对象时可能性太多了)。

还有一种方法也是我们最常用的,就是构造方法就用默认的,每个属性都添加get set方法(JavaBean)。这样创建一个实例很容易,代码也清晰很多。但遗憾的是JavaBean自身有很严重的缺点,因为构造过程被分到了若个个调用中,可能出现不一致状态,导致多线程操作时不安全。

构建器方法既能保证安全性,又能保证可读性。下面大家来看一个例子(食品上的营养成分表):

public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate; public static class Builder {
// 必需参数
private final int servingSize;
private final int servings; // 不必需参数
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0; public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
} public Builder calories(int val) {
calories = val;
return this;
} public Builder fat(int val) {
fat = val;
return this;
} public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
} public Builder sodium(int val) {
sodium = val;
return this;
}
//注意这里,跟Javabean很像,设置了一系列属性之后,Builder调用build方法构建真正的对象
public NutritionFacts build() {
return new NutritionFacts(this);
}
} private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
} }

在客户端我们就可以使用类似于jquery中连缀的这种语法来创建对象了

    public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
}

实际上,就相当于将NutritionFacts类将创建对象的功能委托给了静态内部类Builder。而且,因为static类本身是线程安全的,也避免了javabean的缺陷。

Effective Java2读书笔记-创建和销毁对象(一)的更多相关文章

  1. Effective Java2读书笔记-创建和销毁对象(三)

    第5条:避免创建不必要的对象 本条主要讲的是一些反面教材,希望大家引以为鉴. ①无意中使用自动装箱导致多创建对象. public class Sum { public static void main ...

  2. Effective Java2读书笔记-创建和销毁对象(四)

    第7条:避免使用终结方法 这一条讲的简直是不知所云.先简单记下来其中说出的几条: ①显式终止方法的典型例子有InputStream.OutputStream和java.sql.Connection上的 ...

  3. Effective Java2读书笔记-创建和销毁对象(二)

    第3条:用私有构造器或者枚举类型强化Singleton属性 这一条,总体来说,就是讲了一个小技巧,将构造器声明为private,可以实现单例.具体有以下几种实现的方式. ①最传统的单例实现模式,可能有 ...

  4. Effective Java读书笔记--创建和销毁对象

    1.优先考虑用静态工厂方法代替构造器2.遇到多个构造器参数时要考虑使用构建器Builder解决参数过多,不可变类型.私有构造方法,静态类的构造方法提供必要参数,剩下可选.new xxx.build() ...

  5. Effective Java学习笔记--创建和销毁对象

    创建和销毁对象 一.静态工厂方法代替构造器 静态工厂方法的优缺点 优点: 1.可以自定义名称(可以将功能表述的更加清晰) 2.不必每次调用都创建新的对象(同一对象重复使用) 3.返回的类型可以是原返回 ...

  6. [Effective Java]第二章 创建和销毁对象

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  7. Effective Java2读书笔记-对于所有对象都通用的方法(二)

    第10条:始终要覆盖toString 这一条没什么好讲的,就是说默认的toString方法打印出来的是类名+@+十六进制哈希码的值.我们应该覆盖它,使它能够展示出一些更为详细清晰的信息,这个看实际情况 ...

  8. Effective Java2读书笔记-对于所有对象都通用的方法(一)

    第8条:覆盖equals时请遵守通用约定 ①约定的内容 自反性.对于任何非null的引用值x.x.equals(x)必须返回true. 对称性.对于任何非null的引用值x和y.当且仅当y.equal ...

  9. Effective Java2读书笔记-对于所有对象都通用的方法(三)

    第12条:考虑实现Comparable接口 这一条非常简单.就是说,如果类实现了Comparable接口,覆盖comparaTo方法. 就可以使用Arrays.sort(a)对数组a进行排序. 它与e ...

随机推荐

  1. 谁在唱衰PC?说出你的理由

    在平板电脑的冲击下,PC真的衰落了吗?戴尔消费产品市场副总裁Raymond Wah给出了坚定的回答:“平板电脑没有办法代替PC”. 让他有如此底气做出这一判断的取决于两方面:一方面,PC(了解PC市场 ...

  2. The JRE could not be found.Edit the server and change the JRE location.

    之前更改了了一个较低的jdk的版本看了看一个项目的代码,不知所云,然后再改回来, 混乱之中只要启动Tomcat就出现这种错误,还是无法找到JRE,最后如此解决: 在Windows->Prefer ...

  3. BLOB二进制对象(blob.c/h)

    BLOB二进制对象(blob.c/h) 数据结构 struct blob_attr { uint32_t id_len; /** 高1位为extend标志,高7位存储id, * 低24位存储data的 ...

  4. 【转】android cts测试方法及步骤

    原文网址:http://blog.csdn.net/shi_xin/article/details/42262675 1.CTS下载 打开下面网址, http://source.android.com ...

  5. C# 判断两个日期是否是同一天

    System.Data.Entity.DbFunctions.DiffDays(cs.StartTime.Value,DateTime.Now) == 0//只获取当天 OR XX.StartTime ...

  6. Linux用户基础

    http://itercast.com/lecture/21 操作系统通过用户.组概念来管理使用计算机的人 用户代表一个使用计算机的使用者,操作系统通过用户概念限制一个使用者能够访问的资源 组用来组织 ...

  7. JSP SMARTUPLOAD组件:上传文件时同时获取表单参数

    原因很简单: 注意更改from 属性啊!否则为null! 因为你用jspsmartuploadsmart时post请求 的格式是multipart/form-data,即enctype="m ...

  8. What’s the difference between an interface and an abstract class in Java?

    原文 What’s the difference between an interface and an abstract class in Java? It’s best to start answ ...

  9. wifi_uplink脚本分析

    ~ >: vim apps/tools/wifi_uplink  #!/bin/sh # Copyright (C) 2012 GuoWenxue <guowenxue@gmail.com ...

  10. strut2 自己定义文件上传错误信息

    在文件上传过程中我们能够指定拦截器对文件类型.后缀名.大小进行设定,action中的配置: <interceptor-ref name="fileUpload"> &l ...