第一条:考虑用静态工厂方法代替构造器
静态工厂方法的优点:
1.它们有名称
2.不必在每次调用它们的时候都创建一个新对象(比如单例模式)
3.它们可以返回原返回类型的任何子类型的对象
4.在创建参数化类型实例的时候,它们使代码变得更加简洁
静态工厂方法的缺点:
1.类如果不含公有的或者受保护的构造器,就不能被子类化
2.它们与其他静态方法实际上没有任何区别
静态工厂方法常用名称:
valueOf:该方法返回的实例与它的参数具有相同的值,这样的静态工厂方法实际上是类型转换方法
getInstance:返回的实例是通过方法的参数来描述的,对于Singleton来说,该方法没有参数,并返回唯一实例
newInstance:与getInstance类似,但是newInstance能够确保返回的每个实例都与所有其他实例不同
getType:返回对象类型
1.以Boolean类为例:
/******源码start******/
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
//Boolean类的静态工厂方法
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
/******源码end******/
//使用构造器
Boolean b = new Boolean(true);
//使用静态工厂方法
Boolean b = Boolean.valueOf(true);
2.单例模式
public enum SingleInstance{
INSTANCE;
public void fun(){
//do something
}
}
SingleInstance.INSTANCE.fun();
创建枚举实例的过程是线程安全的,这种写法功能上与共有域方法相近,但是更简洁,无偿地提供了序列化机制,绝对防止对此实例化,即使实在面对复杂的序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法
普通单例:
public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
3.设计模式中的基本的原则之一 —— 【里氏替换】原则,就是说子类应该能替换父类
Class Person{
public static Person getInstance(){
return new Person();
//这里可以改为 return new Student()/Teacher() ;
}
}
Class Student extends Person{}
Class Teacher extends Person{}
4.这条主要是针对带泛型类的繁琐声明而说的,需要重复书写两次泛型参数
Map<String,Object> map = new HashMap<String,Object>();
不过自从 java7 开始,这种方式已经被优化过了 —— 对于一个已知类型的变量进行赋值时,由于泛型参数是可以被推导出,所以可以在创建实例时省略掉泛型参数。
Map<String,Object> map = new HashMap();
第二条:遇到多个构造器参数时要考虑用构造器
静态工厂和构造器都有个共同的局限性:它们不能很好地扩展到大量的可选参数。
此时有三种方法,
一是采用重叠构造器,二是JavaBeans模式,三是Builder模式
package com.chisaki.threadgroup;
/**
*使用重叠构造器模式
**/
public class Person {
//required
private String name;
//optional
private String age;
//optional
private String idType;
//optional
private String idno;
//optional
private String gender;
//optional
private String adress;
public Person(String name) {
this(name,"");
}
public Person(String name,String age) {
this(name,age,"");
}
public Person(String name,String age,String idType) {
this(name,age,idType,"");
}
public Person(String name,String age,String idType,String idno) {
this(name,age,idType,idno,"");
}
public Person(String name,String age,String idType,String idno,String gender) {
this(name,age,idType,idno,gender,"");
}
public Person(String name,String age,String idType,String idno,String gender,String adress) {
this.name = name;
this.age = age;
this.idType = idType;
this.idno = idno;
this.gender = gender;
this.adress = adress;
}
}
重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且难以阅读
/**
*使用JavaBeans模式
*/
public class Person {
private String name;
private String age;
private String idType;
private String idno;
private String gender;
private String adress;
public Person() {}
//setters
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public void setIdType(String idType) {
this.idType = idType;
}
public void setIdno(String idno) {
this.idno = idno;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setAdress(String adress) {
this.adress = adress;
}
}
使用JavaBeans模式有很严重的缺点,因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态,类无法仅仅通过检验构造器参数的有效性来保证一致性。JavaBeans模式阻止了把类做成不可能变的可能,需要付出额外努力来确保他的线程安全。
/**
*使用Builder模式
*/
package com.chisaki.threadgroup;
public class Person {
//必要参数
private String name;
private String age;
//可选参数
private String idType;
private String idno;
private String gender;
private String adress;
public static class Builder{
//必要参数
private final String name;
private final String age;
//可选参数
private String idType = "";
private String idno = "";
private String gender = "";
private String adress = "";
public Builder(String name,String age) {this.name = name;this.age = age;}
public Builder idType(String value) {this.idType = value;return this;}
public Builder idno(String value) {this.idno = value;return this;}
public Builder gender(String value) {this.gender = value;return this;}
public Builder adress(String value) {this.adress = value;return this;}
public Person build() {return new Person(this);}
}
private Person(Builder builder) {
name = builder.name;
age = builder.age;
idType = builder.idType;
idno = builder.idno;
gender = builder.gender;
adress = builder.adress;
}
}
/**
*如何使用Builder模式
*/
Person person = new Person.Builder("yui","18")
.idType("身份证")
.idno("123456789")
.gender("M")
.adress("")
.build();
容易编写且易于阅读,builder模式模拟了具名的可选参数,可与对参数强加约束条件,builder方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对它们进行检验。
使用Builder模式来代替多参数构造函数