避免代码冗余,使用接口和泛型重构Java代码
轉載自?避免代碼冗余,使用接口和泛型重構Java代碼
在使用動態語言和.NET工作了若干年后,我又回到老本行–Java開發。在Ruby中,清除代碼冗余是非常方便的,而在Java中則需要結合接口和泛型實現類似的功能。
原始代碼
以下是這個類中的一些方法用于后續的闡述。為了使例子更簡潔,我移除了些代碼。
| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 | publicV get(finalK key){??Session s;??try{??????s = oGrid.getSession();??????ObjectMap map = s.getMap(cacheName);??????return(V) map.get(key);??}??catch(ObjectGridException oge)??{??????thrownew RuntimeException("Error performing cache operation", oge);??}??finally??{??????if(s != null)??????????s.close();??????????}?????returnnull;}?????publicvoid put(finalK key, finalV value){??Session s;??try{??????s = oGrid.getSession();??????ObjectMap map = s.getMap(cacheName);??????map.upsert(key, value);??}??catch(ObjectGridException oge)??{??????thrownew RuntimeException("Error performing cache operation", oge);??}??finally??{??????if(s != null)??????????s.close();??????????????}???????????}publicMap<K, V> getAll(Set<? extendsK> keys){??finalList<V> valueList = newArrayList<V>();??finalList<K> keyList = newArrayList<K>();??keyList.addAll(keys);??Session s;??try{??????s = oGrid.getSession();??????ObjectMap map = s.getMap(cacheName);??????valueList.addAll(map.getAll(keyList));??}??catch(ObjectGridException oge)??{??????thrownew RuntimeException("Error performing cache operation", oge);??}??finally??{??????if(s != null)??????????s.close();??????????????}??Map<K, V> map = newHashMap<K, V>();??for(inti = 0; i < keyList.size(); i++) {??????map.put(keyList.get(i), valueList.get(i));??}??returnmap;} |
遇到的問題
| 123456789101112131415 | Session s;try{??s = oGrid.getSession();??ObjectMap map = s.getMap(cacheName);??// Some small bit of business logic goes here}catch(ObjectGridException oge){??thrownew RuntimeException("Error performing cache operation", oge);}finally{??if(s != null)??????s.close();????????????} |
上面的代碼段幾乎存在于類的每個方法中,這違反了DRY原則 。將來如果需要改變檢索Session 和 ObjectMap實例的方式,或著某天這段代碼被發現有缺陷,我們就不得不修改每個(包含這段代碼的)方法,因此需要找到一種方式來復用這些執行代碼。
重構后的代碼
為了傳遞包含了原方法中業務邏輯的實例,我們創建一個帶有抽象方法的 Executable 接口 。execute()方法參數為我們欲操作的ObjectMap實例。
| 123 | interfaceExecutable<T> {??publicT execute(ObjectMap map) throwsObjectGridException;} |
由于我們的目的僅僅是在每個方法中操作ObjectMap實例,可以創建executeWithMap()方法封裝前述的那一大段重復代碼。這個方法的參數是Executable接口的實例,實例包含著操作map的必要邏輯(譯者注:這樣Executable接口的實例中就是純粹的業務邏輯,實現了解耦合)。
| 12345678910111213141516171819 | private<T> T executeWithMap(Executable<T> ex){??Session s;??try{??????s = oGrid.getSession();??????ObjectMap map = s.getMap(cacheName);??????// Execute our business logic??????returnex.execute(map);??}??catch(ObjectGridException oge)??{??????thrownew RuntimeException("Error performing cache operation", oge);??}??finally??{??????if(s != null)??????????s.close();??????????????}} |
現在,可以用如下形式的模板代碼替換掉第一個例子中的代碼:這個模板創建了一個匿名內部類,實現了Executable接口和execute()方法。其中execute()方法執行業務邏輯,并以getXXX()的方式返回結果(若為Void方法,返回null)
| 1234567891011121314151617181920212223242526272829303132333435363738 | publicV get(finalK key){??returnexecuteWithMap(newExecutable<V>() {??????publicV execute(ObjectMap map) throwsObjectGridException??????{??????????return(V) map.get(key);??????}??});?????????????}?????publicvoid put(finalK key, finalV value){??executeWithMap(newExecutable<Void>() {??????publicVoid execute(ObjectMap map) throwsObjectGridException??????{??????????map.upsert(key, value);??????????returnnull;??????}??});?????????????}publicMap<K, V> getAll(Set<? extendsK> keys){??finalList<K> keyList = newArrayList<K>();??keyList.addAll(keys);??List<V> valueList = executeWithMap(newExecutable<List<V>>() {??????publicList<V> execute(ObjectMap map) throwsObjectGridException??????{??????????returnmap.getAll(keyList);??????}??});???????????????????????????????Map<K, V> map = newHashMap<K, V>();??for(inti = 0; i < keyList.size(); i++) {??????map.put(keyList.get(i), valueList.get(i));??}??returnmap;} |
FunctionalInterface Annotation (功能接口注釋)
Java 8 的 @FunctionalInterface annotation 使這一切變的簡單。若某接口帶有一個抽象方法,這個接口便可以被用作為lambda表達式的參數,稱為功能接口。
| 1234 | @FunctionalInterfaceinterfaceExecutable<T> {??publicT execute(ObjectMap map) throwsObjectGridException;} |
只要接口僅僅包含一個抽象方法,便可以使用這個annotation。這樣就能減少相當數量的模板代碼。
| 12345678910111213141516171819202122 | publicV get(finalK key){??returnexecuteWithMap((ObjectMap map) -> (V) map.get(key));}?????publicvoid put(finalK key, finalV value){??executeWithMap((ObjectMap map) -> { map.upsert(key, value); returnnull; });}publicMap<K, V> getAll(Set<? extendsK> keys){??finalList<K> keyList = newArrayList<K>();??keyList.addAll(keys);??List<V> valueList = executeWithMap((ObjectMap map) -> map.getAll(keyList));??Map<K, V> map = newHashMap<K, V>();??for(inti = 0; i < keyList.size(); i++) {??????map.put(keyList.get(i), valueList.get(i));??}??returnmap;} |
結論
實現這些重構我很開心。它比原始的代碼略復雜一點,但是更簡明,更DRY,所以一切都是值得的。 盡管還有提升的空間,但這是一個良好的開始。
原文鏈接:? michaelbrameld ?翻譯:? ImportNew.com? -? ImportNew讀者譯文鏈接:? http://www.importnew.com/6761.html
總結
以上是生活随笔為你收集整理的避免代码冗余,使用接口和泛型重构Java代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成都理想one音响升级改装方案来了理想o
- 下一篇: Java8-本地缓存