您的位置:首页 > Web前端

Effective Java读书笔记1

2017-12-21 11:58 155 查看


一. 考虑用静态工厂方法代替构造方法


1. 什么是静态工厂方法

注意与设计模式中的工厂模式是不同的,它是用通过专门定义一个类来负责创建其他类的实例,其实例通常拥有共同的父类,其实现主要是靠Java的反射机制。


2. 静态工厂方法的优点


1.有名称

对于一个对象的实例化来说,如果使用构造方法的话,可以使用构造函数的重载来实现不同情况下的实例化,但是由于构造函数的名称都是类名,只是参数不同,导致可能会错误的调用某些构造函数。

对于静态工厂方法而言,就可以更改方法的名称,对于不同情况的实例化,就可以用不同的静态工厂方法。


2.不必在每次调用它们的时候都创建一个新对象

使用构造函数时,每次实例化都会创建一个新的对象。

但是使用静态工厂方法时,,可以使用构建好的实例或者将构建好的实例缓存起来重复利用。


3.可以返回原类型的任何子类型的对象

主要是利用Java的多态的特性,使工厂可以产生基类的同时加入子类的方法

例:
package com.company;
public class Practice{
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
Aniaml a = AnimalFactory.newInstance("Dog");
a.getinfo();
}
}
interface Aniaml{
public void getinfo();
}
class Dog implements Aniaml{
@Override
public void getinfo() {
System.out.println("I am a dog");
}
}
class Fish implements Aniaml{
@Override
public void getinfo() {
System.out.println("I am a fish");
}
}
class AnimalFactory{
public static Aniaml newInstance(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Aniaml aniaml = null;
aniaml = (Aniaml)Class.forName("com.company."+type).newInstance();
return aniaml;
}
}


运行结果:
I am a dog


通过上面的例子可以看出,使用这种方法就可以得到其他子类的信息。


4.使得代码更加简洁

在原书中,说道在调用参数化类型的构造器时,必须要指明类型参数,例如
Map<String,List<String>> m = new HashMap<String,List<String>>();


但是现在,随着Java版本的更新,现在已经不需要指明类型参数了:以下也是可以的。
Map<String,List<String>> m = new HashMap<>();


3. 静态工厂方法的缺点


1.类如果不包含共有的或者受保护的构造器,就不能被子类化


2.和静态方法实际上没有任何区别。其无法在API文档中明确标出。


二. 遇到多个构造器参数是要考虑用构建器

静态工厂方法和构造器都不能很好的扩展有大量可选参数。

比如有一个类表示包装食品外的营养成分表,其中:每份的含量,每份的卡路里是必选的,但是有超过20个歌可选域:总脂肪量,饱和脂肪量,转换脂肪量等等...

对于这样一个类,怎么编写呢?

1.使用重叠构造器:提供一个只有必选参数的构造器,第二个构造器有一个可选参数,第三个构造器有三个可选参数,以此类推。。。构造的时候就调用含有那些需要的可选参数的最小构造器即可。

但是随着参数的增加,
new Fact(1,2,0,4,5,7)
这样的结构就会变得越来越糟糕,参数过多就会导致很容易出错。

2.JavaBeans模式:即调用setter方法来设置每个需要的参数,这样的代码读起来也很容易。
facts.setServSize(1)
facts.setServing(2)
facts.setCal(4)
facts.setSodium(7)


但是这就阻止了把类做成不可变类的可能,类的属性很容易被修改。

3.Builder模式(构建器):先调用builder的有必要参数的构造器,在调用类似setter的方法来设置每个可选的参数,最后调用无参的build方法生成不可变的Fact对象
class Fact{
private final int servingSize;//必选
private final int servings;//必选
private final int calories;//可选
private final int sodium;//可选

public static class Builder{
private  int servingSize;//必选
private  int servings;//必选

private  int calories = 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 Sodiun(int val){
sodium = val;
return this;
}

public Fact build(){
return new Fact(this);
}
}

private Fact(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
sodium  = builder.sodium;
}
}


构造时:
Fact fact = new Fact.Builder(200,3).Calories(34).Sodiun(67).build();


简而言之:如果类的构造器或者静态工厂方法中有很多参数,设计这种类时,Builder模式就是个不错的选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息