Java經(jīng)典書(shū)籍《Effective Java(第二版)》相信大家都看過(guò),,此書(shū)共有78條關(guān)于編寫(xiě)高質(zhì)量Java代碼的建議,,這里是通俗易懂地講解,,會(huì)持續(xù)全部更新完78條,希望大家每天讀一篇,,一起學(xué)完這78條,,相信可以寫(xiě)出高質(zhì)量代碼。 1.考慮靜態(tài)工廠方法代替構(gòu)造器 通常情況下我們會(huì)利用類的構(gòu)造器對(duì)其進(jìn)行實(shí)例化,,這似乎毫無(wú)疑問(wèn),。但“靜態(tài)工廠方法”也需要引起我們的高度注意。 publica static People getInsatance(){ return new People(); } 它是一個(gè)“方法”,,那么它不同于構(gòu)造器,,它可以隨意修改方法名,這就帶來(lái)第一個(gè)優(yōu)點(diǎn)——有名稱,。有時(shí)一個(gè)類的構(gòu)造器往往不止一個(gè),,而它們的名稱都是相同的,不同的僅僅是參數(shù),,如果不同參數(shù)帶來(lái)不同的含義這樣對(duì)于調(diào)用方來(lái)說(shuō)除了注釋很難理解它們有什么不同的含義,。例如BigInteger(int, int, Random)返回一個(gè)素?cái)?shù),但調(diào)用者很難理解API設(shè)計(jì)者所要想表達(dá)的意思,,如果此時(shí)有BigInteger.probablePrime靜態(tài)工廠方法,,則能一目了然的清楚API設(shè)計(jì)者所要想表達(dá)的含義。舉一個(gè)JDK的例子:Executors類,,在這個(gè)類中有newFixedThread,、newSingleThreadExecutor、newCachedThreadPool等靜態(tài)方法,,因?yàn)樗鼈冇小懊帧?,所有就較為清晰的明白API的含義。 《Effective Java》中所提到的靜態(tài)工廠方法第二個(gè)優(yōu)點(diǎn)在于不用重復(fù)創(chuàng)建一個(gè)對(duì)象,,實(shí)際上也就是勤加載或者稱為餓漢式的單例模式,。例如: public class Instance() { private static Instance instance = new Instance(); private Instance(){} public static Instance getInstance() { return instance; } } 靜態(tài)工廠方法的第三個(gè)優(yōu)點(diǎn),可以返回原返回類型的任何子類型的,。這句話初看不好理解,,舉個(gè)JDK中的例子:Collections類。 List list = Collections.synchroizedList(new ArrayList()) 這個(gè)例子就說(shuō)明了可以返回原返回類型的任何子類型的對(duì)象,。 Map<String,List<String>> map = new HashMap<String,List<String>>()//繁瑣 給集合類提供靜態(tài)工廠方法后: public static <K,V> HashMap<K,V> newInstance(){ return new HashMap<K,V>(); } HashMap<String,List<String>> map = HashMap.newInstance(); 但是實(shí)際上從JDK7(包括JDK7)之后的集合類可以用以下簡(jiǎn)潔的代碼代替: Map<String,List<String>> map = new HashMap<>(); 靜態(tài)工廠方法也有兩個(gè)缺點(diǎn):一是公有的靜態(tài)方法所返回的非公有類不能被實(shí)例化,,也就是說(shuō)Collections.synchronizedList返回的SynchronizedList不能被實(shí)例化,;二是查找API比較麻煩,它們不像普通的類有構(gòu)造器在API中標(biāo)識(shí)出來(lái),,而是和其他普通靜態(tài)方法一樣,,鑒于此,書(shū)中提到了幾種慣用名稱: valueOf 2,遇到不同參數(shù)的多個(gè)構(gòu)造器考慮用構(gòu)建器 你經(jīng)常寫(xiě)一下類似的代碼 public class Student{ private Sring name;
private int age; private String sex; private String grade;
public Student(String name, String sex){ this(name,sex,0); }
public Student(String name,String sex,int age){ this(name,sex,age,''); } this.name=name; this.sex=sex; this.age=age; this.grade=grade; } } 當(dāng)我想實(shí)例化一個(gè)名字叫“kevin”,,性別男,但是不寫(xiě)年齡,,只有年級(jí)“1年級(jí)”,,這個(gè)時(shí)候代碼就:不得不要為年齡這個(gè)參數(shù)傳遞值。如果新增一個(gè)只含年級(jí)的構(gòu)造方法,,那又將多出許多代碼,,更嚴(yán)重的是,如果沒(méi)有一份詳盡的文檔或者注釋,,看到如此多的構(gòu)造方法將無(wú)從下手,,這就是非常常見(jiàn)的重疊構(gòu)造器。 Student student = new Student('joan','male','0','1年假'); 當(dāng)然還有另外一種方法,,只有一個(gè)必填項(xiàng)的構(gòu)造方法,,而其他選填項(xiàng)利用setter方法傳遞。例如: Student student = new Student('joan','male'); student.setGrade('1年級(jí)'),; 這實(shí)際上導(dǎo)致了在構(gòu)造過(guò)程中JavaBean可能處于不一致的狀態(tài),,也就是說(shuō)實(shí)例化對(duì)象本該是一氣呵成,但現(xiàn)在卻分割成了兩大步,,這會(huì)導(dǎo)致它線程不安全,,進(jìn)一步引發(fā)不可預(yù)知的后果。 /** * 構(gòu)建器模式 * Created by yulinfeng on 2017/8/3. */ public class Student { /*必填*/ private String name; private int age; /*選填*/ private String sex; private String grade; public static class Builder { private String name; private int age; private String sex = ''; private String grade = ''; public Builder(String name, int age) { this.name = name; this.age = age; } public Builder sex(String sex) { this.sex = sex; return this; } public Builder grade(String grade) { this.grade = grade; return this; } public Student build() { return new Student(this); } } private Student(Builder builder) { this.name = builder.name; this.age = builder.age; this.sex = builder.sex; this.grade = builder.grade; } } 以上本質(zhì)上是個(gè)靜態(tài)內(nèi)部類 Student student = new Student.Builder('joan','mea').grade('1年級(jí)').build(); 這樣的客戶端代碼很容易邊寫(xiě),,并且便于閱讀。對(duì)于不了解的可能來(lái)說(shuō)利用構(gòu)建器模式編寫(xiě)Student類不算易事,,甚至代碼比重疊構(gòu)造器的代碼更多,。所以當(dāng)可選參數(shù)在很多時(shí),謹(jǐn)慎使用重疊構(gòu)造器,而是使用構(gòu)建器模式,。 今天就這么多了,,明天持續(xù)更新,下期內(nèi)容: 3.用私有構(gòu)造器或者枚舉類型強(qiáng)化Singleton屬性 4.通過(guò)私又構(gòu)造器強(qiáng)化不可實(shí)例的能力 Effective Java(第2版)PDF中英文(有源碼) 下載,。 |
|