静态工厂方法替换构造函数 - 何时替换
- 静态工厂方法含有名字,它能提供更加明确的信息
- 当创建对象的代价很大时,需要使用享元模式时
- 能返回其返回类型的任何子类型的对象(? extends T),比如java .util. collections
- 返回对象的类可以根据输入参数的不同而不同。
- 服务提供者框架中编写包含方法的类时,返回的对象的类不需要存在(这句话,单独拿在这儿来说,我是懵逼的),在书中用JDBC来说明了一下,但解释得十分笼统,这里重新释义一下
服务提供者框架
。
JDBC服务提供者框架关系图.jpg-
Class.forName("com.mysql.jdbc.Driver");
这样一个语句会实例化一个Driver类(提供服务者实现类),并将这个类的实例注册到DriverManager(服务提供者注册类)。 -
DriverManager.getConnection("jdbc:mysql://...","...","...");
这里通过建立连接的URL等信息来获取数据库连接。DriverManager通过传进来的url信息判断出你是要获取那个服务提供者提供的服务。因为1
中已经将提供服务者实现类注册到DriverManager了,DriverManager获取到这个服务提供者实现类对象之后,通过调用它的getService(mysql里面是connect方法)方法获取到服务具体实现类对象,返回的却是java.sql.Connection接口对象(因为服务具体实现类实现了Connection接口),这样把服务具体实现类对象隐藏了。提供了很好的扩展性。 - 在Java1.6的时候加入了java.util.ServiceLoader,可以通过这个类来实现服务提供者。
-
静态工厂方法的常用名称:
-
from
—— A 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant); -
of
—— 一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING); -
valueOf
—— from 和 to 更为详细的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE); -
instance
或getinstance
—— 返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options); -
create
或newInstance
—— 与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen); -
getType
—— 与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:FileStore fs = Files.getFileStore(path); -
newType
—— 与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:BufferedReader br = Files.newBufferedReader(path); -
type
—— getType 和 newType 简洁的替代方式,例如:List litany = Collections.list(legacyLitany);
- tips: 当构造函数的参数过多使用Builder
依赖注入替换硬连接资源的方式
如果一个类依赖于一个或多个底层资源,这些资源的行为会影响类的行为的时候,不要使用单例或静态的实用类来实现这个类,并且不让类直接创建这些资源。相反,将资源或工厂传递给构造方法(或静态工厂或 builder 模式)。这种称为依赖注入的实践将极大地增强类的灵活性、可重用性和可测试性。
重写equals方法
- 自反性: 对于任何非空引用 x,x.equals(x) 必须返回 true。
- 对称性: 对于任何非空引用 x 和 y,如果且仅当 y.equals(x) 返回 true 时 x.equals(y) 必须返回 true。
- 传递性: 对于任何非空引用 x、y、z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,则 x.equals(z) 必须返回 true。
- 一致性对于任何非空引用 x 和 y,如果在 equals 比较中使用的信息没有修改,则 x.equals(y) 的多次调用必须始终返回 true 或始终返回 false。
- 对于任何非空引用 x,x.equals(null) 必须返回 false。
- 当重写 equals 方法时,同时也要重写 hashCode 方法。
- 不要让 equals 方法试图太聪明。如果只是简单地测试用于相等的属性。
- 在 equal 时方法声明中,不要将参数 Object 替换成其他类型。
//正确示范
@Override
public boolean equals(Object o) {
if (!(o instanceof MyType))
return false;
MyType mt = (MyType) o;
...
}
实现Comparable接口
- 使用Arrays.sort来完成排序
- 无论何时实现具有合理排序的值类,都应该让该类实现 Comparable 接口。 比较 compareTo 方法的实现中的字段值时,请避免使用
<
和>
运算符。 相反,使用包装类中的静态 compare 方法或 Comparator 接口中的构建方法。
// BROKEN difference-based comparator - violates transitivity!
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return o1.hashCode() - o2.hashCode();
}
};
/**
*不要使用这种技术!它可能会导致整数最大长度溢出和 IEEE 754 浮点运算失真的危险[JLS 15.20.1,15.21.1]。 此外,由此
*产生的方法不可能比使用上述技术编写的方法快得多。 使用静态 compare 方法:
*/
// Comparator based on static compare method
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
//或者使用 Comparator 的构建方法:
// Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());
//java8 比较 正序
someList.sort((Message m1, Message m2) -> m1.getSendDate().compareTo(m2.getSendDate()));
参考:
-
《effective java》3rd
-- Joshua Bloch - JAVA 服务提供者框架介绍
网友评论