ForCleanCode 为笔者读书总结,出于自身理解目的总结!
一丶对象的创建和销毁
(一) 静态工厂方法替代构造器
1.静态工厂方法的几大优势:
(1) 静态工厂方法与传统构造器方法不同的第一大优势 ,他们有名称:
sample:返回一个素数
public static int BigInteger.probablePrime(int, int, Random){}
(2)不必再每次调用它的时候都创建一个新的对象:
sample:重复利用 预先创建好的实例,如布尔b
/**
* 1 确保他是一个Singleton
* 2 可用 == 替代 equals,判断相等 提升性能
* @param b
* @return
*/
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE:Boolean.FALSE;
}
(3)可以返回原返回类型的任何子类型的对象,提高灵活性
sample: java.util.EnumSet 为例子
/**
* 1 如果他的元素<=64 return RegularEnumSet
* 2 否则 return JumboEnumSet
* 3 class RegularEnumSet> extends EnumSet 都是他的子类
* 4 对客户端不可见 根据参数返回适配类型 更加灵活
* @param elementType
* @param
* @return
*/
public static > EnumSet noneOf(Class elementType) {
Enum>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
(4) 在创建参数化类型实例的时候,使代码变得更加简洁:
sample:已实例化单个HashMap为例子:
/**
* 传统写法
* 缺点:如果HashMap参数 很多 特别冗长 ,实例化起来写长参数 会很麻烦
*/
Map> mMap = new HashMap>();
/**
* 静态工厂方法
* 省下了手写实例化后的参数
*/
Map> mStaticMap = newInstance();
/**
* J神说 目前HashMap 并没有工厂方法(可以放自己的工具类中)
* 在以后java版本中可能会看到
*
* @param
* @param
* @return
*/
public static HashMap newInstance(){
return new HashMap();
}
2丶静态工厂方法的缺点
(1)类如果不含有公有的或者受保护的构造器,就不能被子类化
sample: 比如 Collections 和 Framework, 构造方法私有化 肯定就不能被实例化了。。。。
(2)静态工厂与其他静态方法实际没有任何区别。
sample:
比如你实例化一个TextView 他是通过构造器 实例化的,你找到对应的对象通过Ctrl+左键和容易定位
到 该对象所实例化的构造方法。
但是通过静态工厂 返回给你的实例化对象,是如何实例化的很难找到。
但是J神又说了 Javadoc总有一天会注意到这些静态工厂方法的(但是目前 java8 还没实现 嘻嘻嘻)
(二)遇到多个构造器参数时要考虑用构造器
静态工厂和构造器有个共同的局限性:不能很好的扩展到大量的参数。
(1)从迭代构造器角度考虑:
sample:迭代构造器我们遇到了太多了,比如常见的自定义View
/**
* 根据传入参数的数量挨个迭代,直到三个参数的构造器为止
* Created by zhaoyuanchao on 2018/4/21.
*/
public class SampleView extends View {
public SampleView(Context context) {
this(context, null);
}
public SampleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SampleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
缺点:
构造器调用通常需要许多你根本不想设置的参数,但是由于构造器限制 不得不为他传值, 如果有10个参数那种构造器,就会很快失去控制 相当的不灵活。
(2)JavaBean模式考虑:
sample:可以很好的处理每个必要的可选参数,创建实例容易
/**
* Created by zhaoyuanchao on 2018/4/21.
*/
public class SampleBean {
private String a;
private String b;
public SampleBean() {
}
public void setA(String a) {
this.a = a;
}
public void setB(String b) {
this.b = b;
}
}
缺点:
JavaBean 由于构造过程被分调到了 几个方法中,所以无法通过构造器的有效参数 来保证该类的一致性。
线程不安全。
(3)Builder模式:
sample: 既能保证像构造器那样的安全性,也能保证像JavaBean那样的可读性。
public class NutritionFacts {
private final int a;
private final int b;
private final int c ;
private final int d;
private final int e;
private final int f;
public static class Builder{
// 如 a b 为必须传入的值
private final int a;
private final int b;
// c d e f为非必须传入的值
private int c = 0;
private int d = 0;
private int e = 0;
private int f = 0;
public Builder(int a , int b) {
this.a = a;
this.b = b;
}
public Builder setC(int val){
c = val;
//这里面为什么要为什么要return 自身呢? 为了方便链式调用复制 c d e f
return this;
}
public Builder setD(int val){
d = val;
return this;
}
public Builder setE(int val){
e = val;
return this;
}
public Builder setF(int val){
f = val;
return this;
}
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
a = builder.a;
b = builder.b;
c = builder.c;
d = builder.d;
e = builder.e;
f = builder.f;
}
}
调用方法:
/**
* 很常见一种实例化方法吧,我见过很多
*/
NutritionFacts nutritionFacts = new NutritionFacts.Builder(10, 8).setC(1).
setD(2).setE(3).setF(4).build();
缺点:
(1)为了创建对象,必须先创建Builder的构造器。
(2)Builder模式比重叠构造器更加冗长,只有在多参的时候才会用到(书上推荐>=4个参数)。
Builder模式的应用场景:
如果类的构造器或者静态工厂中有多个参数,Builder模式就是中不错的选择!