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

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

对类而言,为了让客户端获取它自身的一个实例,最常用的方法就是提供一个公有的构造器。还有一种应该被程序员重视的方法:类提供一个公有的静态工厂方法(static factory method),它只是一个返回类的实例的静态方法。下面是来自Boolean(基本类型boolean的包装类)的简单示例,这个方法将boolean基本类型值转换成了一个Boolean对象引用:

1 public static Boolean valueOf(boolean b) {
2 return b?Boolean.TRUE:Boolean.FALSE;
3 }
类可以通过静态工厂方法来提供它的客户端,而不是通过构造器。提供静态工厂方法而不是公有构造器,这样做有几大优势:

静态工厂方法与构造器不同的第一大优势在于,它们有名称。问题:市场上存在三种类型的可乐,不含糖、不含脂和含脂含糖其余的参数一样,请设计一个类用于返回两种不同类型的可乐。

复制代码
1 public class Coca {
2 private final int carbohydrate;
3 private final int calories;
4 private final int fat;
5 private final int sugar;
6 //没问题,返回含糖含脂的可乐
7 public Coca(int carbohydrate, int calories, int fat, int sugar) {
8 super();
9 this.carbohydrate = carbohydrate;
10 this.calories = calories;
11 this.fat = fat;
12 this.sugar = sugar;
13 }
14 //没问题,返回不含糖的可乐实例
15 public Coca(int carbohydrate, int calories, int fat) {
16 super();
17 this.carbohydrate = carbohydrate;
18 this.calories = calories;
19 this.fat = fat;
20 this.sugar = 0;
21 }
22 //预期希望的结果:返回不含脂的可乐实例
23 //编译错误:Duplicate method Coca(int, int, int) in type Coca
24 public Coca(int carbohydrate, int calories, int sugar) {
25 super();
26 this.carbohydrate = carbohydrate;
27 this.calories = calories;
28 this.sugar = sugar;
29 this.fat = 0;
30 }
31 }
复制代码
从上面很明显可以看出,因为构造器区别在于参数类型、个数、顺序不同而已,上面的第三个和第二个构造方法并没有这些不同,因此无法区别才导致报错。这时候,我们幸好有静态工厂方法,我们可以通过使用简单的公共静态方法返回一个类的实例。

复制代码
1 public class Coca {
2 private final int carbohydrate;
3 private final int calories;
4 private final int fat;
5 private final int sugar;
6 private Coca(int carbohydrate, int calories, int fat, int sugar) {
7 this.carbohydrate = carbohydrate;
8 this.calories = calories;
9 this.fat = fat;
10 this.sugar = sugar;
11 }
12 public static Coca includeAllCoca(int carbohydrate, int calories, int fat, int sugar) {
13 return new Coca(carbohydrate,calories,fat,sugar);
14 }
15 public static Coca noFat(int carbohydrate, int calories, int sugar) {
16 return new Coca(carbohydrate,calories,0,sugar);
17 }
18 public static Coca noSugar(int carbohydrate, int calories, int fat) {
19 return new Coca(carbohydrate,calories,fat,0);
20 }
21 }
复制代码
总结:当一个类需要多个带有相同签名的构造器时,就用静态工厂方法代替构造器,并且慎重地选择名称以便突出它们之间的区别。

静态工厂方法与构造器不同的第二大优势在于,不必每次在调用它们的时候都创建一个新的对象。

复制代码

1 public class Elvis {
2 private static final Elvis INSTANCE = new Elvis();
3 private Elvis() {};
4 public static Elvis getInstance() {
5 return INSTANCE;
6 }
7 }
复制代码
静态工厂方法能够为重复的调用返回相同的对象,这样有助于类总能严格控制在某个时刻哪几个实例应该存在,这种类被称为实例受控的类(instance-controlled)。编写实例受控的类有几个原因。

一:实例受控能保证它是一个Singleton或者是不可实例化的。

二:它还使得不可变的类可以确保不会存在两个相等的实例,即当且仅当ab的时候才有a.equals(b)为true,如果能保证这一点,客户端就可以使用来代替equals(Object)方法,这样可以提升性能。

静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型对象。这样我们在选择返回对象的类的时候就有了更大的灵活性。

1 public class Person {
2 public String name;
3 public static Person getInstance() {
4 return new Cooker(); //此处可返回new Cooker()或者new Player()
5 }
6 }
7
8 class Player extends Person{
9
10 }
11
12 class Cooker extends Person{
13 private String food;
14 public Cooker setName(String name) {
15 this.name = name;
16 return this;
17 }
18 public Cooker setFood(String food) {
19 this.food = food;
20 return this;
21 }
22 public void cook() {
23 System.out.println(name+“正在烹饪”+food+",请稍后…");
24 }
25 }

1 Cooker cooker = (Cooker) Person.getInstance();
2 cooker.setName(“XXX”).setFood(“红烧狮子头”).cook();
运行结果:

XXX正在烹饪红烧狮子头,请稍后…
静态工厂方法的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。遗憾的是,在调用参数化类的构造器时,即使类型参数很明显,也必须指明。这通常要求你接连两次提供类型参数:

Map<String,List> m = new HashMap<String,List>();
随着类型参数变得越来越长,越来越复杂,这一冗长的说明也很快变得痛苦起来。但是有了静态工厂方法,编译器就可以替你找到类型参数。这被称作类型推导(type inference)。例如,假设HashMap提供了这个静态工厂:

1 public static <K,V> HashMap<K,V> newInstance(){
2 return new HashMap<K,V>();
3 }
你就可以用下面这句简洁的代码代替上面这段繁琐的声明:

Map<String,List> m = HashMap.newInstance();
静态工厂方法的主要缺点在于,类如果不含公共的或者受保护的构造器,就不能被子类化。例如静态工厂方法的优势二中的例子,该类无法被子类化。

静态工厂方法的第二个缺点在于,它们与其它的静态方法实际上没有任何区别。在API文档中,它们没有像构造器那样在API文档中明确标识出来,因此,对于提供了静态工厂方法而不是构造器的类来说,要想查明如何实例化一个类,这是非常困难的。

下面是静态工厂方法的一些惯用名称:

valueOf-----不太严格地讲,该方法返回的实例与它的参数具有相同的值,这样的静态工厂方法实际上是类型转换的方法。

of-----valueOf的一种更为简洁的替代。

getInstance-----返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于Singleton来说,该方法没有参数,并返回唯一的实例。

newInstance-----像getInstance一样,但是newInstance能够确保返回的每个实例都与所有其它的实例不同。

getType-----像getInstance一样,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。

newType-----像getInstance一样,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。

第1条:考虑采用静态工厂方法代替构造器相关推荐

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

    转载链接:https://www.jianshu.com/p/ceb5ec8f1174 1.序:什么是静态工厂方法 在 Java 中,获得一个类实例最简单的方法就是使用 new 关键字,通过构造函数来 ...

  2. java 静态工厂方法代替构造器的好处

    Java 的静态工厂方法 序:什么是静态工厂方法 Effective Java 2.1 静态工厂方法与构造器不同的第一优势在于,它们有名字 2.2 第二个优势,不用每次被调用时都创建新对象 2.3 第 ...

  3. Java九十条经验法则之第一条:用静态工厂方法代替构造器

    一.用静态工厂方法代替构造器的优势 1.静态构造方法与构造器不同的第一大优势在于,他们有名称,而构造器名字相同,容易混淆,例如: 使用静态构造方式的方式,我们就可以通过知道产生的是什么样类型的对象,而 ...

  4. 静态工厂方法代替构造器实例_静态工厂方法与传统构造方法

    静态工厂方法代替构造器实例 之前,我已经讨论过一些关于Builder模式的信息 , Builder Pattern是一种有用的模式,用于实例化具有几个(可能是可选的)属性的类,这些属性可以使读取,编写 ...

  5. 《Effective Java》学习笔记 - (1) 使用静态工厂方法代替构造器

    文章目录 前言 使用静态工厂方法代替构造器 1. 优点 1.1 静态工厂方法有名称 1.2 不必每次调用的时候都创建一个对象 1.3 可以返回类型的任何子类型的对象 1.4 所返回的对象的类型可以随着 ...

  6. 用静态工厂方法代替构造器

    1.静态工厂方法与构造器不同的第一大优势在于,它们有名称.如果构造器的参数本身没有确切地描述正被返回的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读.例如,构造器Bigin ...

  7. 01、静态工厂方法替代构造器

    考虑用静态工厂方法替代构造器 考虑使用静态工厂方法来替代构造器的原因: 静态工厂方法有名称:普通的构造器中,参数并不能很好地描述返回对象的特点,代码的阅读性不好. 考虑下面的程序: Random ra ...

  8. Effective Java 第一条:考虑用静态工厂方法代替构造器

    优势: 第一条:静态工厂方法有名称,可以从名字看出方法的作用,容易使用. 第二条:不必每次调用都创建一个新对象. 第三条:静态工厂方法可以返回原类型的任何子类型的对象. 第四条:在创建参数化类型的实例 ...

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

    为了获得一个类的实例,有两种办法1.类提供一个公有的构造器 2.类提供一个公有的静态工厂方法. 静态工厂方法的优势: 1.有名称. 慎重地选择方法名称能突出多个构造器的区别,例如使用BigIntege ...

最新文章

  1. Android之在BaseAdapter源码中了解观察者模式
  2. python难学嘛-python语言难学吗
  3. ccf权限查询java_201612-3 ccf 权限查询
  4. 人工智能应用实战系列-如何在新闻推荐中使用迁移学习
  5. Webrtc入门——基于阿里云ubuntu 最新webrtc Android平台编译详细说明
  6. 男人“杀”死女人的30句话
  7. ie6,ie7,ie8 css bug兼容解决记录
  8. devops_面向内向的人的DevOps
  9. “北京链安”近日更名为“中科链安”
  10. 蓝桥杯 ALGO-29 算法训练 校门外的树(区间处理)
  11. 【渝粤教育】电大中专药剂学基础知识 (2)作业 题库
  12. 华为手机字体改简体_华为手机字体怎么更换简体
  13. 目的地址和ARP地址应答中的源地址
  14. 怎么戒网瘾?一个玩了上百款游戏的程序员告诉你有多少废话
  15. jquery-实现的添加个人信息加验证,附完全的注释,相信大家可以看懂
  16. PEI-NaYF4:Yb/Er上转换发光纳米材料,树状水溶性聚合物,45nm粒径纳米粒
  17. 德乐生 java_【Senior Java Developer怎么样】德乐生软件2021年Senior Java Developer前景怎么样-看准网...
  18. [附源码]SSM计算机毕业设计西柚网购物系统JAVA
  19. 如何提供一个短链(URL shorter)生成服务
  20. CDA Day 7-8 Excel 数组学习总结2

热门文章

  1. 喜欢讲故事的“认养一头牛”,能走多远?
  2. 老码农回答为什么会有“在X有Y年的工作经验“这样的要求
  3. PHP友情链接检测,www.jsphp.net友情链接查询结果 - 站长工具
  4. 实验室安全事故读后感
  5. u-boot.lds文件诠释
  6. C语言float是什么类型,float是什么数据类型?
  7. 如何查找SAP notes
  8. 喜马拉雅android sdk接入,喜马拉雅(com.ximalaya.ting.android) - 8.0.1.3 - 应用 - 酷安
  9. 涂鸦智能在香港双重主板上市:市值112亿港元 年营收3亿美元
  10. GDOI#345. 送礼物「JSOI 2015」01分数规划+RMQ